MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

Как да обедините поле на масив в документ в агрегирането на Mongo

TLDR;

Съвременните версии трябва да използват $reduce с $setUnion след първоначалната $group както е показано:

db.collection.aggregate([
  { "$group": {
    "_id": { "Host": "$Host", "ArtId": "$ArtId" },
    "count": { "$sum": 1 },
    "tags": { "$addToSet": "$tags" }
  }},
  { "$addFields": {
    "tags": {
      "$reduce": {
        "input": "$tags",
        "initialValue": [],
        "in": { "$setUnion": [ "$$value", "$$this" ] }
      }
    }
  }}
])

Бяхте прав, когато открихте $addToSet оператор, но когато работите със съдържание в масив, обикновено трябва да обработвате с $unwind първо. Това "денормализира" записите в масива и по същество прави "копие" на родителския документ с всеки запис в масива като единична стойност в полето. Това е, което трябва, за да избегнете поведението, което виждате, без да го използвате.

Вашият „брой“ обаче представлява интересен проблем, но лесно се решава чрез използването на „двойно отвиване“ след първоначална $group операция:

db.collection.aggregate([
    // Group on the compound key and get the occurrences first
    { "$group": {
        "_id": { "Host": "$Host", "ArtId": "$ArtId" },
        "tcount": { "$sum": 1 },
        "ttags": { "$push": "$tags" }
    }},

    // Unwind twice because "ttags" is now an array of arrays
    { "$unwind": "$ttags" },
    { "$unwind": "$ttags" },

    // Now use $addToSet to get the distinct values        
    { "$group": {
        "_id": "$_id",
        "tcount": { "$first": "$tcount" },
        "tags": { "$addToSet": "$ttags" }
    }},

    // Optionally $project to get the fields out of the _id key
    { "$project": {
        "_id": 0,
        "Host": "$_id.Host",
        "ArtId": "$_id.ArtId",
        "count": "$tcount",
        "tags": "$ttags"
    }}
])

Този последен бит с $project също е там, защото използвах "временни" имена за всяко от полетата в други етапи на конвейера за агрегиране. Това е така, защото има оптимизация в $project че "копира" полетата от съществуващ етап в реда, в който вече са се появили, "преди" каквито и да е "нови" полета да бъдат добавени към документа.

В противен случай изходът ще изглежда така:

{  "count":2 , "tags":[ "tag1", "tag2", "tag3" ], "Host": "abc.com", "ArtId": "123" }

Където полетата не са в същия ред, както може би си мислите. Наистина е тривиално, но има значение за някои хора, така че си струва да обясним защо и как да се справите.

Така че $unwind върши работата, за да държи елементите разделени, а не в масиви, и изпълнява $group first ви позволява да получите "броя" на поява на ключа "групиране".

$first Операторът, използван по-късно, "запазва" тази стойност "count", тъй като току-що се "дублира" за всяка стойност, присъстваща в масива "tags". Така или иначе всичко е с еднаква стойност, така че няма значение. Просто изберете един.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Как да оптимизирате производителността на MongoDB

  2. Mongoose Опит за отваряне на незатворена връзка

  3. Регистриране на MongoDB заявки с Spring Boot

  4. Карта-Намаляване на производителността в MongoDb 2.2, 2.4 и 2.6

  5. Mongoose добавя няколко обекта към масива, ако не съществува