Kyle Cureau
Kyle Cureau

Reputation: 19366

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.

Upvotes: 3

Views: 227

Answers (1)

Ashh
Ashh

Reputation: 46461

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
      }
    })
  )
})

Upvotes: 2

Related Questions