Обновить элементы массива по индексу, если они не содержат какого-либо ключа

#mongodb #mongoose #mongodb-query

Вопрос:

Я пытаюсь обновить несколько элементов в массиве в определенном документе, где у меня есть индексы элементов, которые необходимо обновить, только если какой-то ключ не существует.

Ссылка на игровую площадку MongoDB

Предположим, у меня есть документ:

 {
    "key": 1,
    "questions": [
      {
        "text": "first",
      },
      {
        "text": "second",
      },
      {
        "text": "third",
        "answered": "balloon",
      },
    ],
},
 

Я хочу обновить 2-й и 3-й элементы (индексы 2 и 3) новым полем «ответ», но обновите только те, в которых уже нет поля «ответ».
Вот запрос, с которым я справился до сих пор:

 db.collection.update({
  "key": 1,
},
{
  $set: {
    "questions.1.answered": "second answer",
    "questions.2.answered": "third answer",
  }
}
)
 

Это обновление как 2-го, так и 3-го индексов и установка «ответа» для них обоих. Но я хочу пропустить «3-й», поскольку у него уже был «ответный» ключ.
Как я могу добиться этого исключения?
Может быть, что-то в строках ArrayFilters?

Ожидаемый результат:

 {
    "key": 1,
    "questions": [
      {
        "text": "first",
      },
      {
        "text": "second",
        "answered": "second answer", //Added field
      },
      {
        "text": "third",
        "answered": "balloon", //Should not update as it already had "answered"
      },
    ],
},
 

Ответ №1:

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

Запрос

  • в «данные» поместите массив ответов и соответствующие индексы
  • сопоставьте индексы вопросов (0 1 2 ...)
  • проверьте, есть ли индекс в тех, которые необходимо изменить
  • если у них нет ответа, получите ответ

PlayMongo

 update({"key" : 1},
[{"$set": 
    {"data": {"answers": ["index1-a", "index2-a"], "indexes": [1, 2]}}},
  {"$set": 
    {"questions": 
      {"$map": 
        {"input": {"$range": [0, {"$size": "$questions"}]},
          "in": 
          {"$let": 
            {"vars": {"question": {"$arrayElemAt": ["$questions", "$this"]}},
              "in": 
              {"$cond": 
                [{"$and": 
                    [{"$in": ["$this", "$data.indexes"]},
                      {"$eq": [{"$type": "$question.answered"}, "missing"]}]},
                  {"$mergeObjects": 
                    ["$question",
                      {"answered": 
                        {"$arrayElemAt": 
                          ["$data.answers",
                            {"$indexOfArray": ["$data.indexes", "$this"]}]}}]},
                  {"$arrayElemAt": ["$questions", "$this"]}]}}}}}}},
  {"$unset": ["data"]}])