Can I use $push with $ operator?

28 views
Skip to first unread message

jp

unread,
May 11, 2011, 11:25:55 PM5/11/11
to mongodb-user
The following is a theoretical example I am trying to build. What I
wish to do is more complex but presenting this simplified case to
understand if what I want is possible...

Given:

{ "SUBS" : [
{
"_id" : 1,
"VALUE" : 5
}
], "_id" : 1 }
{ "SUBS" : [
{
"_id" : 2,
"VALUE" : 10
}
], "_id" : 2 }
{ "SUBS" : [
{
"_id" : 1,
"VALUE" : 5
}
], "_id" : 3 }

I would like to locate ALL documents who have a subdocument of a
specific _id...I would then like to append a new subdocument to the
array in each of those documents whose new value is derived from the
subdocuments that was located during the query:

db.col.update( { "SUBS._id" : 1 }, { $push : { "SUBS" : { "_id" : 3,
"VALUE" : SUBS.$.VALUE * 5 } } } )

I was hoping for the following result:

{ "SUBS" : [
{
"_id" : 1,
"VALUE" : 5
},
{
"_id" : 3,
"VALUE" : 25
}
], "_id" : 1 }
{ "SUBS" : [
{
"_id" : 2,
"VALUE" : 10
}
], "_id" : 2 }
{ "SUBS" : [
{
"_id" : 1,
"VALUE" : 5
},
{
"_id" : 3,
"VALUE" : 25
}
], "_id" : 3 }


In this example you can see that there were two objects who contained
the subdocument _id:1 and therefore, these two documents got the new
_id:3 appended to its SUBS array.

I have been successful in updating a SUBS document using the same
query but I really need to push a new array subdocument element into
SUBS that makes use of some of the values using the $ operator.


Shouldn't this be possible?

Cheers

Scott Hernandez

unread,
May 11, 2011, 11:34:32 PM5/11/11
to mongod...@googlegroups.com
No, you cannot put expressions, which reference other fields, like that in there. It must be a constant for the update values.



--
You received this message because you are subscribed to the Google Groups "mongodb-user" group.
To post to this group, send email to mongod...@googlegroups.com.
To unsubscribe from this group, send email to mongodb-user...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/mongodb-user?hl=en.


Message has been deleted

jp

unread,
May 12, 2011, 1:24:05 AM5/12/11
to mongodb-user
Any ideas how to work around such a scenario? It is pretty critical
to one of my designs...Mongo's inability to offer access to the
specific subdocuments within an indexed embedded array seems to really
limit its ability to solve some of the more challenging/interesting
problems.

I would expect to be able to know the specifics of what satisfies a
query and thought the $ operator provided that. Seems this is not
possible either:

function( newID )
{
db.col.find(
{ "SUBS._id" : newID } ).forEach(
function( thing )
{
previousValue = thing.SUBS.$.VALUE;
db.col.update(
{ "_id" : thing._id },
{ $push : { "SUBS" :
{ "_id" : newID,
"VALUE" : previousValue * 5 } } } );
} );
}

Since the subdocuments are stored in an arbitrarily ordered array,
even though its is indexed, I can only see what documents contain
these subdocuments, but cannot know which one satisfied the query :(

Any optimal work around would be greatly appreciated...I'm crossing my
fingers, hoping to see such functionality in the near future, I know
there are a number of reported issues/features around this. Is there
anyone on the team looking into designs around such improvements?

Cheers

Scott Hernandez

unread,
May 12, 2011, 8:35:13 AM5/12/11
to mongod...@googlegroups.com
Your code and syntax is perplexing. There is a feature request to allow expressions in the update statement; I can't say how long until it is implemented.

Here is one related issue with doing a query, but the update you are talking about would be very similar in my mind: http://jira.mongodb.org/browse/SERVER-2549

Feel free to add a jira issue for your exact needs and/or provide a patch. http://jira.mongodb.org

On Thu, May 12, 2011 at 1:20 AM, jp <serenitye...@gmail.com> wrote:
Any ideas how to work around such a scenario?  It is pretty critical
to one of my designs...Mongo's inability to offer access to the
specific subdocuments within an indexed embedded array seems to really
limit its ability to solve some of the more challenging/interesting
problems.

I would expect to be able to know the specifics of what satisfies a
query and thought the $ operator provided that.  Seems this is not
possible either:

function( newID )
{
 db.col.find(
   { "SUBS._id" : link._id } ).forEach(

     function( thing )
     {
       previousValue = thing.SUBS.$.VALUE;

       db.col.update(
           { "_id"      : thing._id  },
           { $push : { "SUBS" :
               { "_id"    : newID,
                 "VALUE"  : previousValue * 5 } } } );
     } );
}

Since the subdocuments are stored in an arbitrarily ordered array,
even though its is indexed, I can only see what documents contain
these subdocuments, but cannot know which one satisfied the query :(

Any optimal work around would be greatly appreciated...I'm crossing my
fingers, hoping to see such functionality in the near future, I know
there are a number of reported issues/features around this.  Is there
anyone on the team looking into designs around such improvements?

Cheers

On May 11, 8:34 pm, Scott Hernandez <scotthernan...@gmail.com> wrote:

jp

unread,
May 12, 2011, 3:56:03 PM5/12/11
to mongodb-user
Sorry I tried to make the sample as simple as I can think of and I see
where I am missing an input :P, should be:

function( previousID, newID )
{
db.col.find(
{ "SUBS._id" : previousID } ).forEach(
function( thing )
{
previousValue = thing.SUBS.$.VALUE;
db.col.update(
{ "_id" : thing._id },
{ $push : { "SUBS" :
{ "_id" : newID,
"VALUE" : previousValue * 5 } } } );
} );
}


The primary purpose of the query is to determine if a primary document
contains the subdocument having SUBS._id:previousID within its array/
list of SUBS. If it does contain the subdocument, I need to use some
of its values to generate a new subdocument to store in the same
primary document. Note that there can be many primary documents
containing this particular previousID, thus I need to $push this new
subdocument to each of those primary documents' SUBS array/list. I am
sorry the example does not look like it fits any real use case, but I
cannot disclose any specifics about the actual use case. What is
needed is to:

A.) Index a subdocument contained within an array of the primary
document (Mongo can handle this)
B.) Be able to query for the primary document based on its
subdocuments fields (No problem here)
C.) I need to know which subdocument was matched, thus which satisfied
the query expression (Sadly, I cannot see how this is possible in
Mongo)
D.) Lastly I need to retrieve data from the subdocument that satisfied
the query (I do not see a way to do this either)

The only work around I can think of is to de-normalize my schema and
move the subdocuments out into their own collection. This brings be
back to a simple row structure. The problem I have is that this de-
normalization defeats the purpose of using the document oriented
benefits of Mongo. This is an area I see lacking most in Mongo. It
may be fast, but we are limited mostly to manipulation of the primary
document, but it is challenged when trying to retrieve, access and
manipulate its subdocuments.

The de-normalized approach is also less efficient since uniqueness is
defined by primary._id and SUBS._id and thus I would have to include
another ID value that ensure uniqueness, but serves no purpose in the
design. This table will get extremely large and keeping it light as
possible is critical.

I figured this was possible since Mongo offers the $ operator and I
would be able to update SUBS.$.VALUE, but in my case I do not want it
updated I want to know its value so I can use it to update/create
something else.

Cheers


On May 12, 5:35 am, Scott Hernandez <scotthernan...@gmail.com> wrote:
> Your code and syntax is perplexing. There is a feature request to allow
> expressions in the update statement; I can't say how long until it is
> implemented.
>
> Here is one related issue with doing a query, but the update you are talking
> about would be very similar in my mind:http://jira.mongodb.org/browse/SERVER-2549
>
> Feel free to add a jira issue for your exact needs and/or provide a patch.http://jira.mongodb.org

Scott Hernandez

unread,
May 12, 2011, 3:59:28 PM5/12/11
to mongod...@googlegroups.com
Javascript doesn't work that way. You have mixed things together which don't work; like oil and vinegar.

There are requests which allow you to do what you want but nothing like the syntax you are using; there will be no javascript run like that. 

jp

unread,
May 12, 2011, 6:56:58 PM5/12/11
to mongodb-user
From my point of view I am not trying to get JS to do, but I am trying
to have the located subdocument available to me within the context of
the update...If you took JavaScript out of the equation (see my
earliest example) I still see huge value (and immediate need ;) in the
following (regardless of syntax, it is the functionality I seek):

db.col.update( { "SUBS._id" : 1 }, { $push : { "SUBS" : { "_id" : 3,
"VALUE" : SUBS.$.VALUE * 5 } } } )

If I wanted to update the actual SUBS document that was located I
could:

db.col.update( { "SUBS._id" : 1 }, { $set : { "SUBS.$.VALUE" :
55555 } } )

Unfortunately, this is not what I need...It does seem to mean that
during the update the engine has some pointer to the actual value that
was located which satisfied the query (I know it is limited to only 1
subdocument at the moment and would be happy with that for now I know
I am looking for one and only one within an individual primary
document). As can be seen here, we are setting the value in the
located subdocument...Rather, I need to be able to use that located
value to set, update, insert into the located primary document
something new.

I do not see why the coding for one does not also make the other
possible (though I understand this functionality is not currently
present). If there seems to be no particular work around to do this
type of operation on the server side (very critical to my project)
then I will make the proposal for enhancement along these lines within
JIRA and see where that takes us.

Cheers



On May 12, 12:59 pm, Scott Hernandez <scotthernan...@gmail.com> wrote:
Reply all
Reply to author
Forward
0 new messages