Как избежать добавления повторяющихся объектов в массив в MongoDB - PullRequest
1 голос
/ 16 июня 2020

это моя схема:

 new Schema({
    code: { type: String },
    toy_array: [
      {
        date:{
        type:Date(),
        default: new Date()
       }
        toy:{ type:String }
    ]
   }

это моя база данных:

{
  "code": "Toystore A",
  "toy_array": [
    {
      _id:"xxxxx", // automatic
      "toy": "buzz"
    },
    {
      _id:"xxxxx", // automatic
      "toy": "pope"
    }
  ]
},
{
  "code": "Toystore B",
  "toy_array": [
    {
       _id:"xxxxx", // automatic
      "toy": "jessie"
    }
  ]
}

Я пытаюсь обновить объект. В этом случае я хочу обновить документ с помощью code: 'ToystoreA' и добавить массив поддокументов в массив с именем toy_array, если игрушки не существуют в массиве.

, например, если я попытаюсь сделать это :

db.mydb.findOneAndUpdate({
  code: 'ToystoreA,
  /*toy_array: {
    $not: {
      $elemMatch: {
        toy: [{"toy":'woddy'},{"toy":"buzz"}],
      },
    },
  },*/
},
{
  $addToSet: {
    toy_array: {
      $each: [{"toy":'woddy'},{"toy":"buzz"}],
    },
  },
},
{
  new: false,
}
})

они добавлены, и это то, чего я хочу избежать.

как я могу это сделать?

[
  {
    "code": "Toystore A",
    "toy_array": [
      {
        "toy": "buzz"
      },
      {
        "toy": "pope"
      }
    ]
  },
  {
    "code": "Toystore B",
    "toy_array": [
      {
        "toy": "jessie"
      }
    ]
  }
]

В этом примере [{"toy":'woddy'},{"toy":"buzz"}] должно быть добавляется только 'woddy', потому что 'buzz' уже находится в массиве.

Примечание: когда я вставляю новый toy, в дополнение к _id также вставляется дата вставки (это нормально для меня ).

1 Ответ

2 голосов
/ 16 июня 2020

Поскольку вы используете $ addToSet на объекте, он не подходит для вашего варианта использования по какой-то причине:

Допустим, если ваш документ выглядит так:

    {
      _id: 123, // automatically generated
      "toy": "buzz"
    },
    {
      _id: 456, // automatically generated
      "toy": "pope"
    }

и ввод:

[{_id: 789, "toy":'woddy'},{_id: 098, "toy":"buzz"}]

Здесь при сравнении двух объектов {_id: 098, "toy":"buzz"} & {_id: 123, "toy":"buzz"} - $addToSet учтите, что они разные, и вы не можете использовать $addToSet в поле (toy) в объекте. Поэтому попробуйте запрос ниже по версии MongoDB> = 4.2.

Запрос:

db.collection.updateOne({"_id" : "Toystore A"},[{
    $addFields: {
      toy_array: {
        $reduce: {
          input: inputArrayOfObjects,
          initialValue: "$toy_array", // taking existing `toy_array` as initial value
          in: {
            $cond: [
              { $in: [ "$$this.toy", "$toy_array.toy" ] }, // check if each new toy exists in existing arrays of toys
              "$$value", // If yes, just return accumulator array
              { $concatArrays: [ [ "$$this" ], "$$value" ] } // If No, push new toy object into accumulator
            ]
          }
        }
      }
    }
  }])

Тест: URL-адрес теста конвейера агрегации: mongoplayground

Ссылка: $ уменьшить

Примечание:

Нет Не нужно указывать { new: false } как .findOneAndUpdate(), возвращать старый do c по умолчанию, если вам нужен новый, вы должны сделать { new: true }. Также, если кто-то может избавиться от _id из схемы объектов массива, вы можете просто использовать $addToSet, как это делал ранее OP (предположим, если _id - только уникальное поле), проверьте это stop-mon goose -from-create-id-property-for-sub-document-array-items .

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