Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add array values into MongoDB where element is not in array

In MongoDB, this is the simplified structure of my account document:

{
    "_id" : ObjectId("5a70a60ca7fbc476caea5e59"),
    "templates" : [ 
        {
            "name" : "Password Reset",
            "content" : "AAAAAAAA"
        },
        {
            "name" : "Welcome Message",
            "content" : "BBBBBB"
        }
     ]
}

There's a similar default_templates collection

let accnt = await Account.findOne({ _id: req.account._id }, { templates: 1 });
let defaults = await DefaultTemplate.find({}).lean();

My goal is to find the missing templates under account and grab them from defaults. (a) I need to upsert templates if it doesn't exist in an account and (b) I don't want to update a template if it already exists in an account.

I've tried the following:

if (!accnt.templates || accnt.templates.length < defaults.length) {

  const accountTemplates = _.filter(accnt.templates, 'name');
  const templateNames = _.map(accountTemplates, 'name');

  Account.update({ _id: req.account._id, 'templates.name' : { $nin: templateNames } },
      { '$push': { 'templates': { '$each' : defaults } } }, { 'upsert' : true },
      function(err, result) {
        Logger.error('error %o', err);
        Logger.debug('result %o', result);
      }
  );
}

This succeeds at the upsert but it will enter all default templates even if there's a matching name in templateNames. I've verified that templateNames array is correct and I've also tried using $addToSet instead of $push, so I must not understand Mongo subdoc queries.

Any ideas on what I'm doing wrong?

Edit: I've gotten this to work by simply removing elements from the defaults array before updating, but I'd still like to know how this could be accomplished with Mongoose.

like image 555
Kyle Cureau Avatar asked Aug 22 '26 18:08

Kyle Cureau


1 Answers

You can try with bulkWrite operation in mongodb

Account.bulkWrite(
  req.body.accountTemplates.map((data) => 
    ({
      updateOne: {
        filter: { _id: req.account._id, 'templates.name' : { $ne: data.name } },
        update: { $push: { templates: { $each : data } } },
        upsert : true
      }
    })
  )
})
like image 98
Ashh Avatar answered Aug 25 '26 13:08

Ashh