sql >> Database teknologi >  >> NoSQL >> MongoDB

MongoDB sortering vs aggregeret $sort på matrixindeks

Aggregeringsrammen "beskæftiger sig med" arrays på samme måde, som anvendes på .find() forespørgsler generelt. Dette gælder ikke kun for operationer som .sort() , men også med andre operatører, og nemlig $slice , selvom det eksempel er ved at blive rettet (mere senere).

Så det er stort set umuligt at håndtere noget ved at bruge "dot notation"-formen med et indeks for en matrixposition, som du har. Men der er en vej uden om dette.

Det, du "kan" gøre, er grundlæggende at finde ud af, hvad det "n'te" array-element faktisk er som en værdi, og derefter returnere det som et felt, der kan sorteres:

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

Det er en forfærdelig og "iterabel" tilgang, hvor du i det væsentlige "træder igennem" hvert array-element ved at få $first match pr. dokument fra arrayet efter behandling med $ slappe af . Så efter $unwind igen tester du for at se, om disse array-elementer er de samme som dem, der allerede er "set" fra de identificerede array-positioner.

Det er forfærdeligt og værre for de flere positioner, du ønsker at flytte langs, men det får resultatet:

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

Heldigvis får kommende udgivelser af MongoDB (som i øjeblikket tilgængelig i udviklingsudgivelser) en "fix" til dette. Det er måske ikke den "perfekte" løsning, du ønsker, men det løser det grundlæggende problem.

Der er en ny $slice operatør tilgængelig for aggregeringsrammen der, og den vil returnere det eller de nødvendige elementer i arrayet fra de indekserede positioner:

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

Som producerer:

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

Så du kan bemærke, at som et "udsnit" er resultatet stadig et "array", men $sort i aggregeringsrammen har altid brugt den "første position" af arrayet for at sortere indholdet. Det betyder, at med en enkeltværdi udtrukket fra den indekserede position (ligesom den lange procedure ovenfor), så vil resultatet blive sorteret, som du forventer.

Slutsagen her er, at det er bare sådan, det fungerer. Enten lev med den slags operationer, du har brug for ovenfra for at arbejde med en indekseret position af arrayet, eller "vent", indtil en helt ny skinnende version kommer dig til undsætning med bedre operatører.




  1. return Model.create(arr).exec() virker ikke i mongoose

  2. redis - Brug af hashes

  3. Hvordan gør jeg MongoDB-forespørgsel til en JSON?

  4. Kør Mahout RowSimilarity-anbefaling på MongoDB-data