Skip to content

Update array doc - mention that the array field must appear last in the query argument #997

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

sperelson
Copy link

Discovered that if there is any ambiguity with fields in the query argument, the array element that is identified will not be updated unless the specific array field that identifies the array element is the last item in the query argument.

Discovered that if there is any ambiguity with fields in the query argument, the array element that is identified will not be updated. Unless the specific array field that identifies the array element is the last item in the query argument.
@ghost ghost assigned kay-kim May 16, 2013
@kay-kim
Copy link
Contributor

kay-kim commented May 17, 2013

Hi sperelson --
As you mentioned, using $elemMatch ensures that a single element in the array matches all the specifying conditions.
Otherwise, just using the comma-delinated conditions means that the query will match the array field as a whole if if either a single array element meets the conditions or a combination of array elements meet the conditions.

For instance, given a collection with the following document

db.test.findOne()
{
"_id" : ObjectId("51964b0a7306bbbcb42bb6f5"),
"myField" : [
{ "a" : 5,
"b" : 6,
"_id" : "kay"
},
{
"_id" : "kay2",
"a" : 10,
"b" : 10
}
]
}

The following query will match myField because myField has an element with the field _id = 'kay' and another element with the field a = 10, so as a whole myField matches.

db.test.find( { 'myField._id': 'kay', 'myField.a': 10 } ).pretty()
{
"_id" : ObjectId("51964b0a7306bbbcb42bb6f5"),
"myField" : [
{
"a" : 5,
"b" : 6,
"_id" : "kay"
},
{
"_id" : "kay2",
"a" : 10,
"b" : 10
}
]
}

More importantly, for your use case at hand, the ordering of the query does not guarantee that the right element is updated. For instance, I ran the following in sequence (I edited down the document for clarity sake)

db.doc.findOne()
{
"_id" : ObjectId("517129fa954634251900002b"),
"content" : {
"content" : [
{
"id" : "14146-13eaa371d30-6cd3",
"definition" : {
"description" : "HTML Widget first element",
"options" : {
"htmlcontent" : {
"value" : "hello"
}
}
},
"wid" : "html"
},
{
"id" : "e7c0-13eaa291804-148f5",
"definition" : {
"description" : "Text Widget 2nd element",
"options" : {
"fgcolor" : {
"value" : ""
},
"text" : {
"value" : "testing"
}
}
},
"wid" : "text"
},
{
"id" : "14146-13eaa371d30-6cd3",
"definition" : {
"description" : "HTML Widget 3rd element",
"options" : {
"htmlcontent" : {
"value" : "goodbye"
}
}
},
"wid" : "html"
},
{
"id" : "c8c0-23eaa291804-de456",
"definition" : {
"description" : "Text Widget 4th element",
"options" : {
"fgcolor" : {
"value" : ""
},
"text" : {
"value" : "Another"
}
}
},
"wid" : "text"
}
],
"description" : "Standard page",
"version" : "1"
},
"pagetitle" : "home"
}

I ran your first update statement with the "Another" condition as the first instead of last:

db.doc.update(
... {
... "content.content.definition.options.text.value" : "Another",
... "_id" : ObjectId("517129fa954634251900002b"),
... "content.content.definition.options.fgcolor.value" : "",
... "content.content.id" : "c8c0-23eaa291804-de456"
... },
... {
... $set :
... {
... "content.content.$.definition.options.text.value" : "Another2",
... "content.content.$.definition.options.fgcolor.value" : ""
... }
... })

As you can see, in my collection, the update statement updated the 4th element

db.doc.findOne()
{
"_id" : ObjectId("517129fa954634251900002b"),
"content" : {
"content" : [
{
"id" : "14146-13eaa371d30-6cd3",
"definition" : {
"description" : "HTML Widget first element",
"options" : {
"htmlcontent" : {
"value" : "hello"
}
}
},
"wid" : "html"
},
{
"id" : "e7c0-13eaa291804-148f5",
"definition" : {
"description" : "Text Widget 2nd element",
"options" : {
"fgcolor" : {
"value" : ""
},
"text" : {
"value" : "testing"
}
}
},
"wid" : "text"
},
{
"id" : "14146-13eaa371d30-6cd3",
"definition" : {
"description" : "HTML Widget 3rd element",
"options" : {
"htmlcontent" : {
"value" : "goodbye"
}
}
},
"wid" : "html"
},
{
"definition" : {
"description" : "Text Widget 4th element",
"options" : {
"fgcolor" : {
"value" : ""
},
"text" : {
"value" : "Another2"
}
}
},
"id" : "c8c0-23eaa291804-de456",
"wid" : "text"
}
],
"description" : "Standard page",
"version" : "1"
},
"pagetitle" : "home"
}

So, I believe the ordering of the query conditions are not quite coupled to which element will be selected to update. But as you correctly figured out yourself, using $elemMatch ensures that the query finds the element in the array that matches all the array element conditions.

I'm going to close this pull request; however, I will definitely add explanation of the behavior regarding arrays.

Thanks again for taking the time to work through this. Much appreciated.

Regards,

Kay

@kay-kim kay-kim closed this May 17, 2013
mongo-cr-bot pushed a commit that referenced this pull request Apr 21, 2022
* DOCS-15182 BACKPORT loadRoutingTableOnStartup

* Staging fixes
mongodb-server-docs-sync-bot bot pushed a commit that referenced this pull request Jun 23, 2025
* no index submodule version 1.24.1

* No index for no-submodule filex 1.24.1

* netlify (#915)

---------

Co-authored-by: John Williams <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants