Обновить подмассив объектов в mongodb - PullRequest
1 голос
/ 16 февраля 2020

У меня есть этот документ в моей базе данных:

{
    "_id": "ObjectId(...)",
    "chapters": [
        {
            "_id": "ObjectId(...)",
            "link": "128371.html",
            "content": ""
        }
    ]
}

Массив разделов может содержать до 3 тыс. Элементов, и мне необходимо заполнить каждый атрибут содержимого некоторой информацией. Я хочу сохранить информацию, которую я хочу, в нужном объекте. До сих пор я мог изменять атрибут содержимого в целом (во всех элементах), но у меня возникают проблемы с его фильтрацией. Вот что мне удалось закодировать, используя то, что я нашел в других вопросах:

let content = "Testing";
await models.ListNovel.updateOne(
  { link: novel_link },
  { $set: { "chapters.$[].content": content } }
);

Я видел, что { arrayFilters: [{ link: { $eq: chapter_link } }], multi: false } может работать в некоторых случаях, но я не использую идентификатор ссылки в обновлении.

Спасибо!

ОБНОВЛЕНИЕ

Как и в решении Сулеймана, я получил следующий рабочий код, надеюсь, он вам пригодится.

await models.ListNovel.updateOne(
  { link: novel.link },
  { $set: { "chapters.$[elem].content": content } },
  {
    multi: true,
    arrayFilters: [{ "elem.link": { $eq: chapter.link } }]
  }
);

1 Ответ

1 голос
/ 16 февраля 2020

Условие в updateOne должно соответствовать родительскому объекту, но вы используете { link: novel_link }, который принадлежит полю поля внутреннего массива, поэтому он не может найти документ и обновление не происходит.

Чтобы проиллюстрировать это, предположим, что ваша схема выглядит следующим образом:

const mongoose = require("mongoose");

const schema = new mongoose.Schema({
  name: String,
  chapters: [
    new mongoose.Schema({
      link: String,
      content: String
    })
  ]
});

module.exports = mongoose.model("ListNovel", schema);

Давайте иметь этот существующий документ в этой коллекции:

{
    "_id": "5e498a1fe21eea0e10690e39",
    "name": "Novel1",
    "chapters": [
        {
            "_id": "5e498a1fe21eea0e10690e3b",
            "link": "128371.html",
            "content": ""
        },
        {
            "_id": "5e498a1fe21eea0e10690e3a",
            "link": "222222.html",
            "content": ""
        }
    ],
    "__v": 0
}

Если мы хотим обновить главу этого документа с помощью "link": "128371.html", сначала нам нужно найти его с именем или полем _id и обновить его, используя отфильтрованный позиционный оператор $ .

router.put("/novels/:name", async (req, res) => {
  const novel_link = "128371.html";
  const content = "Testing";

  const result = await ListNovel.findOneAndUpdate(
    { name: req.params.name },
    {
      $set: { "chapters.$[chapter].content": content }
    },
    {
      arrayFilters: [{ "chapter.link": novel_link }],
      new: true
    }
  );
  res.send(result);
});

Здесь я использовал findOneAndUpdate для немедленного получения обновленного документа, но вы также можете использовать updateOne вместо findOneAndUpdate.

Результат будет таким:

{
    "_id": "5e498a1fe21eea0e10690e39",
    "name": "Novel1",
    "chapters": [
        {
            "_id": "5e498a1fe21eea0e10690e3b",
            "link": "128371.html",
            "content": "Testing"  // => UPDATED
        },
        {
            "_id": "5e498a1fe21eea0e10690e3a",
            "link": "222222.html",
            "content": ""
        }
    ],
    "__v": 0
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...