I am trying to update/upsert a Mongo Collection based on documents elements and the elements of some arrays in the document, and I'm having trouble. I have read the MongoDB documentation on positional-all (looks like: $[]
) and positional-filtered ( looks like: $[element]
) and I have also read seemingly similar questions and answers here on Stackoverflow but I still can't figure it out.
The Example from MongoDB
The working example that the MongoDB docs gives is:
db.collection.update(
{ myArray: [ 0, 1 ] },
{ $set: { "myArray.$[element]": 2 } },
{ arrayFilters: [ { element: 0 } ],
upsert: true }
)
What I am trying to figure out is, what if myArray instead of being:
[0,1]
is an array of objects like [{"num": 1, "name": "X"}, {"num": 2, "name": "Y"}]
An Example of My Collection:
var myCollection =
[
{ "name": "Design", "price": 499, "users": [{"username": "A", "profiles": 0} ,{"username": "B", "profiles": 2}, {"username": "C", "profiles": 9} ], "face_to_face": 2 },
{ "name": "Launch", "price": 999, "users": [{"username": "A", "profiles": 0} ,{"username": "R", "profiles": 6}, {"username": "X", "profiles": 10} ], "face_to_face": 4 },
{ "name": "Scale", "price": 1499, "users": [{"username": "B", "profiles": 0} ,{"username": "F", "profiles": 5}, {"username": "G", "profiles": 12} ], "face_to_face": 8 }
]
What I am trying to do in English:
Look for documents that match on "name" and, within those documents, if there's an element of "users" with a given value for "username," then update that with the given value of "profiles", but if there's not an element with that value of "username" then push a new element (with the given values for "username" and "profiles") to the array "users." If there's not a document matching on "name" then create that document (including name, price, and the array users, which should have one entry at the start with the given values of username and profiles.
Here is the code I am trying to use to implement the update/upsert:
const updateObj = {
"$set": {
"name":areaName
, "price": areaPrice
, "face_to_face": 0
,"users.$[element].username" : thisUserName
,"users.$[element].profiles" : countProfiles
}
myCollection.updateMany({
"name": areaName
,"users": {"$elemMatch": {"username": thisUserName}}
}, updateObj, {
arrayFilters: { "element.username": thisUserName }],
upsert: true
}).exec();
But that's not working and gives the following error:
The path 'users' must exist in the document in order to apply array updates.
I suspected this is because my query is not specifying that "users" is an array.
I have also tried this:
myCollection.updateMany({
"name": areaName
,"users": [{"username": thisUserName}]
}, updateObj, {
arrayFilters: [ { "element.username": thisUserName }],
upsert: true
}).exec();
But the trouble there (I think) is that it's not properly querying the documents since "users" is an array with multiple keys (username, profiles) instead of just one key (username) given in the query here.
I also tried this:
myCollection.updateMany({
"name": areaName
,"users": []
}, updateObj, {
arrayFilters: [ { "element.username": thisUserName }],
upsert: true
}).exec();
But the "upsert" part of this is not working. It's creating a document, but the array users is just empty []
instead of [{"username": thisUserName, "profiles": countProfiles ].
Help?
PS Sorry I can't paste a mongo DB sandbox or something, can't find one that allows for .update().