MongoDB: обновить внешний массив и вложенные массивы в одном обновлении - PullRequest
0 голосов
/ 28 марта 2020

Структура документа в коллекции cities выглядит следующим образом

города

  {
   _id:  ObjectId("5e78ec62bb5b406776e92fac"),
   city_name: "Mumbai",
   ...
   ...
   subscriptions: [
    {
       _id: 1,
       category: "Print Magazine",
       subscribers: 183476
       options: [
         {
            name: "Time",
            subscribers: 56445
         },
         {
            name: "The Gentlewoman",
            subscribers: 9454
         },
         {
            name: "Gourmand",
            subscribers: 15564
         }
         ...
         ...
       ]
     },
     {
       _id: 2,
       category: "RSS Feed",
       subscribers: 2645873
       options: [
         {
            name: "Finance",
            subscribers: 168465
         },
         {
            name: "Politics",
            subscribers: 56945
         },
         {
            name: "Entrepreneurship",
            subscribers: 56945
         },
         ...
         ...
       ]
     }
   ]
}

Теперь, когда пользователь подписывается, как показано ниже

{
  cityId: 5e78ec62bb5b406776e92fac
  selections: [
    {
      categoryId: 1,
      options : ["Time", "Gourmand"]
    }, 
    {
      categoryId: 2, 
      selected: ["Politics", "Entrepreneurship"]
    }    
  ]
}

Я хочу обновить следующее в cities документе

  • Увеличить подписчиков на "Print Magazine" на 1
    • Увеличить подписчиков на "Time" на 1
    • Увеличение числа подписчиков на "Gourmand" на 1
  • Увеличение числа подписчиков на "RSS-канал" на 1
    • Увеличение количества подписчиков на "Политику" на 1
    • Увеличьте число подписчиков для «Предпринимательства» на 1

. Таким образом, когда элемент подписан, число его подписчиков увеличивается на 1. И в категорию, в которую он попадает, его число подписчиков также увеличено на 1.

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

Подробности использования

Сведения о подписке каждого пользователя хранятся в коллекции user_subscription_details (здесь нет в списке). Свойство subscriptions в cities содержит только сведения о подписке для каждого города.

1 Ответ

0 голосов
/ 29 марта 2020

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

db.cities.updateOne(
{
   _id : ObjectId("5e78ec62bb5b406776e92fac")
},
{ 
   $inc: { 
     "subscriptions.$[category].subscribers" : 1,
     "subscriptions.$[category].options.$[option].subscribers" : 1
   }
},
{ multi: true,
   arrayFilters: [
     { "category._id": {$in: ["1", "2"]} },
     { "option.name": {$in: ["Time", "Gourmand", "Politics", "Entrepreneurship"]} } 
   ]
}
)

Краткое пояснение

  • Сначала документ сопоставляется с _id.
  • В блоке обновления мы объявим поля для обновления
    • "подписки. $ [?]. Подписчики": 1,
    • "подписки. $ [?]. options. $ [?]. подписчики ": 1

Я использовал ? здесь, чтобы показать, что мы еще не знаем для какие элементы в массиве нам нужно сделать, чтобы эти обновления. Это мы можем объявить в следующем блоке, отфильтровывая элементы массива, которые необходимо обновить.

  • В блоке фильтра мы фильтруем элементы массива по некоторому условию
    • {"category ._id ": {$ in: [" 1 "," 2 "]}}
    • {" option.name ": {$ in: [" Time "," Gourmand "," Politics "," Entrepreneurship "]}}

Сначала мы фильтруем элементы во внешнем массиве по _id, т.е. только по категориям подписок, для которых _id равно 1 или 2. Далее мы фильтруем элементы во внутреннем массиве options в поле name. Элементы, которые пройдут оба фильтра, будут обновлены.

Примечание: category в category._id и option в option.name могут иметь любое имя. Но то же имя будет использоваться для пути к полям в блоке обновления.

Для перевода этого запроса Spring Boot MongoOperation посмотрите на этот ответ

...