Элементы массива условного обновления MongoDB

#javascript #node.js #arrays #mongodb #mongoose

Вопрос:

Я использую Мангуста в Node.js серверная часть и мне нужно обновить подмножество элементов массива в документе на основе условия. Раньше я выполнял операции с помощью функции save(), как это:

 const channel = await Channel.findById(id);
  channel.messages.forEach((i) =>
    i._id.toString() === messageId amp;amp; i.views < channel.counter
      ? i.views  
      : null
  );
  await channel.save();
 

Я хотел бы изменить этот код с помощью findByIdAndUpdate, поскольку это всего лишь приращение, и в моем случае нет необходимости извлекать документ. Есть какие-нибудь предложения о том, как я могу выполнить операцию?

Конечно, channel.messages-это обсуждаемый массив. представления и счетчик имеют номер типа.

РЕДАКТИРОВАТЬ — Пример документа:

 {
    "_id": {
            "$oid": "61546b9c86a9fc19ac643924"
    },
    "counter": 0,
    "name": "#TEST",
    "messages": [{
        "views": 0,
        "_id": {
            "$oid": "61546bc386a9fc19ac64392e"
        },
        "body": "test",
        "sentDate": {
            "$date": "2021-09-29T13:36:03.092Z"
        }
    }, {
        "views": 0,
        "_id": {
            "$oid": "61546dc086a9fc19ac643934"
        },
        "body": "test",
        "sentDate": {
            "$date": "2021-09-29T13:44:32.382Z"
        }
    }],
    "date": {
        "$date": "2021-09-29T13:35:33.011Z"
    },
    "__v": 2
}
 

Комментарии:

1. Можете ли вы добавить пример документа?

2. @J. F. да, конечно

Ответ №1:

Вы можете попробовать updateOne метод, если не хотите получать документ в результате,

  • совпадают как поля id , так и messageId условия
  • проверьте условие выражения, $filter чтобы повторить цикл messages массива и проверить messageId views , меньше ли и counter , тогда он вернет результат, а $ne условие проверит, что результат не должен быть пустым
  • $inc чтобы увеличить views на 1, если запрос совпадает, используя $ позиционный оператор
 messageId = mongoose.Types.ObjectId(messageId);
await Channel.updateOne(
  {
    _id: id,
    "messages._id": messageId,
    $expr: {
      $ne: [
        {
          $filter: {
            input: "$messages",
            cond: {
              $and: [
                { $eq: ["$this._id", messageId] },
                { $lt: ["$this.views", "$counter"] }
              ]
            }
          }
        },
        []
      ]
    }
  },
  { $inc: { "messages.$.views": 1 } }
)
 

Игровая площадка