Home > Net >  Can you do a $pull in a MongoDB Bulk Write which has an array of update operations?
Can you do a $pull in a MongoDB Bulk Write which has an array of update operations?

Time:09-27

Version: MongoDB v 4.2.18.

I have the following MongoDb script I'm trying to run in the MongoDB Shell:

const operations = [ {
    
    "updateOne" : {
                "filter" : { <snipped> },
                "update" : [
                        { "$pull" : { <snipped> } },
                        { "$set" : { <snipped> } }
                ]
        }
} ]

db.accounts.bulkWrite(operations);
  • I've snipped out the schema for the filter, pull and set. I've used them before in single operations and they worked 100% fine.
  • BulkWrite is good when you've got an array of operations. This example has one atomic operation. I've just removed the other items, for simplicity of this question. So please don't say "don't use BW. just do a normal Update query".

The shell basically errors with:

WriteCommandError({
    "ok" : 0,
    "errmsg" : "Unrecognized pipeline stage name: '$pull'",
    "code" : 40324,
    "codeName" : "Location40324"
})

So, can you do a $pull in a MongoDB Bulk Write which has an array of update operations?

Btw, this works, if I:

  • don't do 2x atomic operations, but just one
  • don't do an array of operations
const operations = [ {
    
    "updateOne" : {
                "filter" : { <snipped> },
                "update" : { "$pull" : { <snipped> } }
        }
} ]

Finally, I've found some information in the official docs about $pull and bulkWrite but the example they give only has a single operation, not an array of operations. As highlighted above, I can get it working if I have a single operation (like the example). But I cannot with an array :(

CodePudding user response:

The syntax your using for the update is the aggregation pipeline update snytax, this means you're executing a limited "aggregation pipeline" as your update body.

$pull is not an aggregation expression which means it cannot be used in an aggregation pipeline. $set is working for you because it does have an aggregate version.

So if you want to keep the current logic we just have to use an aggregation operator that can do the same thing $pull can, Specifically the $filter operator seems like a good fit:

const operations = [
    {
        "updateOne": {
            "filter": {},
            "update": [
                {
                    "$set": {
                        arrayYouPullFrom: {
                            $filter: {
                                $input: "$arrayYouPullFrom",
                                cond: {$ne: ["$$this", "valueToPull"]}
                            }
                        }
                    }
                },
                {"$set": {}}
            ]
        }
    }
]

db.accounts.bulkWrite(operations);
  • Related