sql >> Databáze >  >> NoSQL >> MongoDB

MongoDB řazení vs agregace $sort na indexu pole

Agregační rámec prostě „nezachází s“ poli stejným způsobem, jaký je aplikován na .find() dotazy obecně. To neplatí pouze pro operace jako .sort() , ale i s jinými operátory, a to konkrétně $slice , ačkoli tento příklad bude brzy opraven (více později).

Takže je téměř nemožné vypořádat se s čímkoli pomocí "tečkové notace" formy s indexem pozice pole, jako máte vy. Ale existuje způsob, jak to obejít.

Co "můžete" udělat, je v podstatě zjistit, co je vlastně "n-tý" prvek pole jako hodnotu, a pak to vrátit jako pole, které lze třídit:

  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 } }
  ])

Je to hrozný a „opakovatelný“ přístup, kdy v podstatě „procházíte“ každý prvek pole získáním $first shodu na dokument z pole po zpracování pomocí $ uvolnit . Poté po $unwind znovu otestujete, zda jsou tyto prvky pole stejné jako ty, které již byly "viděny" z identifikovaných pozic pole.

Je to hrozné a horší pro více pozic, na kterých se chcete pohybovat, ale má to výsledek:

{ "_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 }

Naštěstí nadcházející vydání MongoDB (jak je aktuálně k dispozici ve vývojových verzích) dostanou „opravu“. Nemusí to být "dokonalá" oprava, kterou si přejete, ale řeší základní problém.

Je zde nový $slice operátor dostupný pro tamní agregační rámec a vrátí požadované prvky pole z indexovaných pozic:

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

Což produkuje:

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

Můžete si tedy všimnout, že jako „slice“ je výsledkem stále „pole“, nicméně $sort v agregačním rámci vždy používal "první pozici" pole, aby seřadil obsah. To znamená, že se singulární hodnotou extrahovanou z indexované pozice (stejně jako dlouhý postup výše) bude výsledek seřazen podle očekávání.

Zde jsou konečné případy, jak to funguje. Buď žijte s druhem operací, které shora potřebujete, abyste mohli pracovat s indexovanou pozicí pole, nebo „počkejte“, až vás zachrání zbrusu nová nablýskaná verze s lepšími operátory.




  1. Nasazení aplikace Meteor na vlastní server

  2. jaký je střední rozdíl mezi drahokamy Nest a redis-namespace, když používáme redis s rails/ruby

  3. Konektor dřezu kafka mongodb se nespouští

  4. Fungování dekorátoru @cache_page() v django-redis-cache