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

$lookup на ObjectId в масив

Актуализация за 2017 г.

$lookup вече може директно да използва масив като локално поле. $unwind вече не е необходимо.

Стар отговор

$lookup Етапът на конвейера на агрегация няма да работи директно с масив. Основната цел на дизайна е за "ляво присъединяване" като тип "един към много" (или наистина "търсене") на възможните свързани данни. Но стойността е предназначена да бъде единична, а не масив.

Следователно първо трябва да "денормализирате" съдържанието, преди да извършите $lookup операция, за да работи това. А това означава да използвате $unwind :

db.orders.aggregate([
    // Unwind the source
    { "$unwind": "$products" },
    // Do the lookup matching
    { "$lookup": {
       "from": "products",
       "localField": "products",
       "foreignField": "_id",
       "as": "productObjects"
    }},
    // Unwind the result arrays ( likely one or none )
    { "$unwind": "$productObjects" },
    // Group back to arrays
    { "$group": {
        "_id": "$_id",
        "products": { "$push": "$products" },
        "productObjects": { "$push": "$productObjects" }
    }}
])

След $lookup съответства на всеки член на масива, резултатът е самия масив, така че $unwind отново и $group до $push нови масиви за крайния резултат.

Обърнете внимание, че всички съвпадения на "лявото присъединяване", които не са намерени, ще създадат празен масив за "productObjects" на дадения продукт и по този начин ще отричат ​​документа за елемента "product", когато вторият $unwind се нарича.

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

Като $lookup по принцип е много нов, в момента работи както би било познато на тези, които са запознати с mongoose като "версия за бедни хора" на .populate() предлаган там метод. Разликата е, че $lookup предлага обработка от страна на сървъра на "join" за разлика от клиентската и че част от "зрелостта" в $lookup в момента липсва от това, което .populate() оферти (като интерполиране на търсенето директно в масив).

Това всъщност е възложен проблем за подобрение на SERVER-22881, така че с малко късмет ще се появи следващата версия или скоро след това.

Като принцип на проектиране, текущата ви структура не е нито добра, нито лоша, а просто подлежи на режийни разходи при създаване на каквото и да е "присъединяване". Като такъв се прилага основният постоянен принцип на MongoDB в началото, където ако „можете“ да живеете с данните, „предварително присъединени“ в една колекция, най-добре е да го направите.

Другото нещо, което може да се каже за $lookup като общ принцип е, че целта на "присъединяването" тук е да работи обратното, отколкото е показано тук. Така че вместо да се съхраняват „свързаните идентификатори“ на другите документи в „родителския“ документ, общият принцип, който работи най-добре, е, когато „свързаните документи“ съдържат препратка към „родителя“.

Така че $lookup може да се каже, че "работи най-добре" с "дизайн на релации", който е обратен на нещо като mongoose .populate() извършва свързвания от страна на клиента. Като вместо това идентифицирате "един" във всяко "много", тогава просто изтегляте свързаните елементи, без да е необходимо да $unwind първо масива.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Не може да се свърже с mongodb errno:61 Връзката е отказана

  2. Как да заявя MongoDB с like

  3. Как да получа последните N записи в mongodb?

  4. 8 начина да получите деня от дата в MongoDB

  5. Изберете Групиране по брой и отделен брой в същата заявка за mongodb