How do I update/set/unset a key in embedded document/array in MongoDB?

1,986 views
Skip to first unread message

Sam

unread,
Oct 13, 2011, 3:06:32 PM10/13/11
to mongodb-user
I am trying to unset all values in a document that's embedded in an
array. Let's say I have a collection coll with array things,
containing a value myval. I want to unset myval. This looks like:

{ things: [{ myval: 1 }, { myval: 2 }] }
I've tried both

db.coll.update({}, {$unset: {'things.myval': 1}})

and

db.coll.things.update({}, {$unset: {'myval': 1}})

Neither of these work. I can't find any documentation online
describing how to do this.

Any help would be appreciated! Thanks in advance.

Brandon Diamond

unread,
Oct 13, 2011, 3:26:11 PM10/13/11
to mongodb-user
What is the desired outcome of the operation? Should myval be null? Or
simply removed?

Note that update will only hit a single document; you want to make
sure your selector targets the appropriate document or you enable the
multi-update flag.

- Brandon

Brandon Diamond

unread,
Oct 13, 2011, 3:31:51 PM10/13/11
to mongodb-user
Here's a simple example that illustrates how you could simply drop a
field from an object contained within an array:

// start with a bunch of documents within an array
> db.test.find()
{ "_id" : ObjectId("4e973b8d51081c4d0a2a31b4"), "a" : [ { "b" : 1 },
{ "b" : 2 }, { "b" : 3 }, { "b" : 4 }, { "b" : 5 } ] }

// find a document with field a containing an object with b bound to 2
// use the positional operator ("$") to substitute the corresponding
index position and unset
> db.test.update({ "a.b": 2 }, { "$unset": { "a.$.b": 1 } })

// it's gone!
> db.test.find()
{ "_id" : ObjectId("4e973b8d51081c4d0a2a31b4"), "a" : [ { "b" : 1 },
{ }, { "b" : 3 }, { "b" : 4 }, { "b" : 5 } ] }


Hope this helps,
- Brandon

Sam Grossberg

unread,
Oct 13, 2011, 4:10:22 PM10/13/11
to mongod...@googlegroups.com
OK, that helps - did not know about multi update or positional operator. However, I'm still not quite there - I'm trying to eliminate ALL of the 'b' keys. From the documentation, it sounds like this might not be possible with the positional operator: 
Currently the $ operator only applies to the first matched item in the query (http://www.mongodb.org/display/DOCS/Updating)

db.test.update({}, { "$unset": { "a.$.b" : 1 } }, false, true)

is my latest iteration, but that doesn't seem to work. Do I need to write a giant for loop? :(

--
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.


Sam Millman

unread,
Oct 13, 2011, 5:01:36 PM10/13/11
to mongod...@googlegroups.com
Positional operator only works when looking for something so:

db.test.update({'a.b': 1}, { "$unset": { "a.$.b" : 1 } }, false, true)

But then that is quite points cos you might as well do:

db.test.remove({ 'a.b' : 1 });

Sam Millman

unread,
Oct 13, 2011, 5:02:35 PM10/13/11
to mongod...@googlegroups.com
Oh wait I see your removing a field, missed that part. My first example would then be better.

The second will ofc remove the entire document.

Sam Grossberg

unread,
Oct 13, 2011, 5:15:23 PM10/13/11
to mongod...@googlegroups.com
I'm trying to delete all fields where 'a.b' = anything...

Brandon Diamond

unread,
Oct 13, 2011, 5:26:07 PM10/13/11
to mongodb-user
Look into "$pullAll" -- that might be what you're looking for.

On Oct 13, 5:15 pm, Sam Grossberg <sam.grossb...@gmail.com> wrote:
> I'm trying to delete all fields where 'a.b' = anything...
>
>
>
>
>
>
>
> On Thu, Oct 13, 2011 at 2:02 PM, Sam Millman <sam.mill...@gmail.com> wrote:
> > Oh wait I see your removing a field, missed that part. My first example
> > would then be better.
>
> > The second will ofc remove the entire document.
>
> > On 13 October 2011 22:01, Sam Millman <sam.mill...@gmail.com> wrote:
>
> >> Positional operator only works when looking for something so:
>
> >> db.test.update({'a.b': 1}, { "$unset": { "a.$.b" : 1 } }, false, true)
>
> >> But then that is quite points cos you might as well do:
>
> >> db.test.remove({ 'a.b' : 1 });
>
> >> On 13 October 2011 21:10, Sam Grossberg <sam.grossb...@gmail.com> wrote:
>
> >>> OK, that helps - did not know about multi update or positional operator.
> >>> However, I'm still not quite there - I'm trying to eliminate ALL of the 'b'
> >>> keys. From the documentation, it sounds like this might not be possible with
> >>> the positional operator:
> >>> Currently the $ operator only applies to the *first* matched item in the
> >>> query (http://www.mongodb.org/display/DOCS/Updating)
>
> >>> db.test.update({}, { "$unset": { "a.$.b" : 1 } }, false, true)
>
> >>> is my latest iteration, but that doesn't seem to work. Do I need to write
> >>> a giant for loop? :(
>

Sam Grossberg

unread,
Oct 13, 2011, 5:28:32 PM10/13/11
to mongod...@googlegroups.com
Hmm...looks like I need to specify an array of values for that? The value could be any integer...

Sam Millman

unread,
Oct 13, 2011, 5:38:46 PM10/13/11
to mongod...@googlegroups.com
find({ 'a.b': { $nin: {null}}}, {$unset: { 'a.$.b': 1 }}, false, true);

this basically says:

where a.b is not null unset it.

This might work

Brandon Diamond

unread,
Oct 13, 2011, 6:03:14 PM10/13/11
to mongodb-user
My mistake; I misunderstood the question.

If you want to remove all subobjects wherein a certain condition holds
true, you can use $pull with a sub-object selector (i.e., the selector
passes will be used to filter the array contents). Here's a quick
example:

> db.stuff.save({ 'arr': [ {'a': 1},{'a':2},{'a':2},{'a':3},{'a':2},{'a':3},{'a':3} ] })
> db.stuff.find()
{ "_id" : ObjectId("4e975f86955abc3e60f6d464"), "arr" :
[ { "a" : 1 }, { "a" : 2 }, { "a" :
2 }, { "a" : 3 }, { "a" : 2 },
{ "a" : 3 }, { "a" : 3 } ] }
> db.stuff.update({}, { '$pull': { 'arr': { 'a': 2 } } })
> db.stuff.find()
{ "_id" : ObjectId("4e975f86955abc3e60f6d464"), "arr" : [ { "a" : 1 },
{ "a" : 3 }, { "a" : 3 }, { "a" : 3 } ] }
>


- Brandon

On Oct 13, 5:38 pm, Sam Millman <sam.mill...@gmail.com> wrote:
> find({ 'a.b': { $nin: {null}}}, {$unset: { 'a.$.b': 1 }}, false, true);
>
> this basically says:
>
> where a.b is not null unset it.
>
> This might work
>
> On 13 October 2011 22:28, Sam Grossberg <sam.grossb...@gmail.com> wrote:
>
>
>
>
>
>
>
> > Hmm...looks like I need to specify an array of values for that? The value
> > could be any integer...
>

Sam Grossberg

unread,
Oct 13, 2011, 7:14:00 PM10/13/11
to mongod...@googlegroups.com
Hmm. Targeting with $nin in the query didn't work. I don't think $pull is what I'm looking for - that removes the entire object, right? I don't want to remove the entire object from the array, I want to just remove the one key.

Before:
a: [{ 'b': 1, 'c': 11 }, {'b': 2, 'c': 12}]

After:
a: [{ 'c': 11}, {'c': 12}]

Latest attempt:
db.a.update({'a.b': {$nin: [null]}}}, {$unset: {'a.$.b':1}})

Jeff Iacono

unread,
Oct 13, 2011, 7:27:15 PM10/13/11
to mongodb-user
I had to unset a temp field (new_sender / new_commenter) that
contained multiple embedded documents in the conversations and posts
collection. To do this, I looped through the collections and then
updated each main document to unset the temp field. This was a one off
thing so it was a down and dirty implantation, so ymmv - might be
helpful and could serve as a base that you can work off of.

https://gist.github.com/8a9617584a2e3301c87b
Reply all
Reply to author
Forward
0 new messages