Добавить значения массива в MongoDB, где элемент не находится в массиве

В MongoDB это упрощенная структура моего документа account:

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

Есть похожая коллекция default_templates

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

Моя цель - найти недостающие шаблоны в учетной записи и получить их по умолчанию. (а) Мне нужно обновить templates, если он не существует в учетной записи, и (б) я не хочу обновлять шаблон, если он уже существует в учетной записи.

Я пробовал следующее:

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

Это будет успешным при обновлении, но он войдет во все шаблоны по умолчанию, даже если в templateNames есть соответствующее имя. Я проверил, что массив templateNames правильный, и я также пробовал использовать $addToSet вместо $push, поэтому я не должен понимать запросы вложенного документа Mongo.

Есть идеи о том, что я делаю неправильно?

Обновлено: я заставил это работать, просто удалив элементы из массива значений по умолчанию перед обновлением, но я все же хотел бы знать, как это можно сделать с помощью Mongoose.

что содержат templateNames и defaults?

Ashh 27.07.2018 04:40

@AnthonyWinzlet по умолчанию содержит документ / схему, идентичную показанной выше для account. TemplateNames содержит массив этих свойств name в том же документе (например, [ "Password Reset", "Welcome Message" ])

Kyle 27.07.2018 14:37

upsert работает на уровне документа, а не суб-документов. addToSet работает (например, не нажимает) только тогда, когда и имя, и контент идентичны. Ваш подход таков, как он должен работать.

Alex Blex 27.07.2018 15:41

Единственное, $ nin делает не то, что вы ожидаете. Он сопоставляет только документы, в которых нет единого шаблона с именем из templateNames, что несколько отличается от «поиска отсутствующих шаблонов».

Alex Blex 27.07.2018 15:47
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
3
4
164
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете попробовать с операцией bulkWrite в 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
      }
    })
  )
})

Другие вопросы по теме