Добавить элемент в массив, если он существует, не добавлять его, если он существует, обновить его - PullRequest
1 голос
/ 03 апреля 2020

Я делаю систему голосования, в которой у объекта будет массив с именем scores, каждый раз, когда он квалифицирован, запись будет добавляться в этот массив, пока такой же идентификатор не существует.

Образец Do c:

{
 name:"jose luis",
 scores:[]
}

Пользователь pu sh:

{id:1,stars:5}

Обновлен Do c:

{
 name:"jose luis",
 scores:[{id:1,stars:5}]
}

Пользователь pu sh 2-й раз:

{id:1,stars:4}

Обновлен Do c:

{
 name:"jose luis",
 scores:[{id:1,stars:4}]
}  //this should update the value of the stars under the array element with the existing id.

Я пробовал это:

   Politico.update(
        { name: "jose luis" },
        {
            $setOnInsert: { "$scores.id": body.req.id},
            "$addToSet": {
                scores: {
                    "id": body.req.id,
                    "starts": body.req.stars
                }
            }


        },
        { upsert: true }

Я пробовал это, но это не работает, как я могу это исправить? Большое спасибо.

1 Ответ

1 голос
/ 04 апреля 2020

На MongoDB 4.2 или выше, так как вы можете использовать агрегационный конвейер в обновлениях, попробуйте следующий запрос:

Politico.updateOne(
  { name: "jose luis" },
  [{
    $addFields: {
      scores: {
        $reduce: {
          input: "$scores",
          initialValue: [{ id: 1, stars: 5 }], // Input
          in: {
            $cond: [
              { $in: ["$$this.id", "$$value.id"] }, /** Check id exists in 'scores' array */
              "$$value", /** If YES, return input */
              { $concatArrays: ["$$value", ["$$this"]] }/** If NO, concat value(holding array) with current object as array */
            ]
          }
        }
      }
    }
  }]);

Возможно, вам не нужно { upsert: true }, поскольку вы не пишу новый документ с name : "jose Luis" и соответствующим scores массивом. Но если вы хотите сделать это:

Politico.updateOne(
  { name: "jose luis" },
  [{
    $addFields: {
      scores: {
        $reduce: {
          input: "$scores",
          initialValue: [{ id: 1, stars: 5 }], // Input
          in: {
            $cond: [
              { $in: ["$$this.id", "$$value.id"] }, /** Check id exists in 'scores' array */
              "$$value", /** If YES, return input */
              { $concatArrays: ["$$value", ["$$this"]] }/** If NO, concat value(holding array) with current object as array */
            ]
          }
        }
      }
    }
  },
  {$addFields : {scores : { $ifNull: [ "$scores", {id : 13, stars: 3} ] }}} /** This additional 'addFields' will add 'scores' array with input object to newly created doc */
],{upsert : true});

Тест: MongoDB-Playground

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...