I'm looking for a way to implement some kind of if item is not there, insert it; if it's there and it holds a condition, replace it; if it's there and it doesn't fulfill the condition, ignore it.
I thought about a upsert statement with a pipeline composing a match-stage and a replaceRoot-stage, but match doesn't work with update-pipelines :-(
For example these cases are necessary (while there is an unique index on title
):
Before: {title:'Some cool title', version: 5, value: 'foo', anotherValue: 'val'}
After: {title:'Some cool title', version: 15, value: 'bar'}
Before: {title:'Some cool title', version: 16, value: 'foo', anotherValue: 'val'}
After: {title:'Some cool title', version: 16, value: 'foo', anotherValue: 'val'}
Before: <'Some cool title' is missing>
After: {title:'Some cool title', version: 15, value: 'bar'}
Do you know how I can implement this kind of update statement?
CodePudding user response:
So you specify 3 conditions but from the update perspective it really is only 2.
- Execute replacement (if doesn't exist this upserts)
- Don't do anything.
You're approach you tried is the correct approach, I'm assuming you just ran into some syntex issues, here is how to do it:
const newData = {title:'Some cool title', version: 15, value: 'bar', timestamp: new Date()};
db.collection.updateOne({
"title": "Some cool title"
},
[
{
"$replaceRoot": {
"newRoot": {
$cond: [
{
$gt: [
newData.timestamp,
"$timestamp"
]
},
newData, //if newData timestamp is gt the document timestamp ( this is also true if document doesn't exist ) use the newData
"$$ROOT" // else the condition fails just use the same old root.
]
},
}
}
],
{
"upsert": true
})