Home > Net >  Conditional upsert with MongoDB
Conditional upsert with MongoDB

Time:08-24

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.

  1. Execute replacement (if doesn't exist this upserts)
  2. 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
})

Mongo Playground

  • Related