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

MongoDB сортиране срещу обобщено $sort на индекс на масив

Рамката за агрегиране просто не "работи" с масиви по същия начин, както се прилага към .find() заявки като цяло. Това не е вярно само за операции като .sort() , но също и с други оператори, а именно $slice , въпреки че този пример е на път да получи корекция (повече по-късно).

Така че е почти невъзможно да се справим с каквото и да било, използвайки формата за "точкова нотация" с индекс на позиция на масив, какъвто имате. Но има начин да се заобиколи това.

Това, което „можете“ да направите, е основно да разберете какво всъщност представлява „n-тият“ елемент от масива като стойност и след това да го върнете като поле, което може да бъде сортирано:

  db.test.aggregate([
    { "$unwind": "$items" },
    { "$group": { 
      "_id": "$_id",
      "items": { "$push": "$items" },
      "itemsCopy":  { "$push": "$items" },
      "first": { "$first": "$items" }
    }},
    { "$unwind": "$itemsCopy" },
    { "$project": {
      "items": 1,
      "itemsCopy": 1,
      "first": 1,
      "seen": { "$eq": [ "$itemsCopy", "$first" ] }
    }},
    { "$match": { "seen": false } },
    { "$group": {
      "_id": "$_id",
      "items": { "$first": "$items" },
      "itemsCopy": { "$push": "$itemsCopy" },
      "first": { "$first": "$first" },
      "second": { "$first": "$itemsCopy" }
    }},
    { "$sort": { "second": -1 } }
  ])

Това е ужасен и „итерируем“ подход, при който по същество „минавате през“ всеки елемент от масива, като получавате $first съвпадение на документ от масива след обработка с $ размотавам . След това след $unwind отново тествате, за да видите дали тези елементи на масива са същите като този(ите), които вече са „виждани“ от идентифицираните позиции на масива.

Ужасно е и още по-лошо за колкото повече позиции искате да се придвижите, но резултатът се получава:

{ "_id" : 2, "items" : [ 0, 3, 4 ], "itemsCopy" : [ 3, 4 ], "first" : 0, "second" : 3 }
{ "_id" : 1, "items" : [ 1, 2, 0 ], "itemsCopy" : [ 2, 0 ], "first" : 1, "second" : 2 }
{ "_id" : 3, "items" : [ 2, 1, 5 ], "itemsCopy" : [ 1, 5 ], "first" : 2, "second" : 1 }

За щастие, предстоящите издания на MongoDB (както в момента са налични в изданията за разработка) получават „поправка“ за това. Може да не е „идеалното“ решение, което желаете, но решава основния проблем.

Има нов $slice оператор, наличен за рамката за агрегиране там, и ще върне необходимия елемент(и) на масива от индексираните позиции:

  db.test.aggregate([
    { "$project": {
      "items": 1,
      "slice": { "$slice": [ "$items",1,1 ] }
    }},
    { "$sort": { "slice": -1 } }
  ])

Което произвежда:

{ "_id" : 2, "items" : [ 0, 3, 4 ], "slice" : [ 3 ] }
{ "_id" : 1, "items" : [ 1, 2, 0 ], "slice" : [ 2 ] }
{ "_id" : 3, "items" : [ 2, 1, 5 ], "slice" : [ 1 ] }

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

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




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. MongoDB Агрегиране с $sample много бавно

  2. Грешка:няма отворени връзки в Db._executeQueryCommand Node.js

  3. Как да тествате надстройките на приложението си MongoDB?

  4. Spring Boot Standard UUID кодек не работи с AbstractMongoClientConfiguration

  5. MongoDb заявка за получаване на максимално поле в масива