I have MongoDB users
collection with the (simplified) document structure:
{
_id: ObjectId,
name: 'John Doe',
sportsList: [ // array of objects
{
name: 'football',
level: 1500,
levelHistory: [ // array of objects
{
from: 1450,
to: 1500,
date: Date
},
...
]
},
{
name: 'tennis',
level: 1400,
levelHistory: [ // array of objects
{
from: 1350,
to: 1400,
date: Date
},
...
]
},
]
}
I want to update the element of sportsList
that has the name === 'tennis'
like this:
- push a new element into
levelHistory
- update the
level
So far I've managed to push a new element intolevelHistory
with this query:
await User.updateOne(
{
_id: userId,
sportsList: {
$elemMatch: { name: 'tennis' }
}
},
{
$push: {
'sportsList.$.levelHistory': {
date: Date,
from: 1400,
to: 1450
}
},
// how do I set 'level: 1450' in the same query?
// if I tried to use a $set: { 'sportsList.$.level': 1450 } mongoDB throws an error
}
)
CodePudding user response:
Query
- pipeline update requires MongoDB >= 4.2
- map on the array
- if name is not tennis don't change the element
- else merge the element(embedded document) with a document that has the new level, and the new levelHistory (the concat of the old, with the new element)
update(
{"_id": 1},
[{"$set":
{"sportsList":
{"$map":
{"input": "$sportsList",
"in":
{"$cond":
[{"$ne": ["$$this.name", "tennis"]}, "$$this",
{"$mergeObjects":
["$$this",
{"level": 1450,
"levelHistory":
{"$concatArrays":
["$$this.levelHistory",
[{"from": 1400, "to": 1450, "date": 4}]]}}]}]}}}}}])