2017-05-28 2 views
1

Ich habe ein Mungo-Schema als solche definiert:Dokumente abrufen, wo Summe von Größen von Arrays größer als gegebener Wert

const hackathonSchema = new mongoose.Schema({ 
    hackathonId: {type: Number, required: true}, 
    uuid: {type: String, required: true}, 
    data: {type: Object, required: true}, 
    isPublished: {type: Boolean, default: false}, 
    organisers: [String], 
    volunteers: [String], 
    participants: [String], 
    mentors: [String] 
}); 

export default mongoose.model('Hackathon', hackathonSchema); 

ich alle Hackathons abrufen möchten, wo die Länge:

(organisers + volunteers + participants +mentors) >= 500 

oder irgendein Wert für diese Angelegenheit.

fand ich eine Antwort von SO, das dies tut, aber in Mungo nicht How to select where sum of fields is greater than a value in MongoDB

Antwort

1

einfach die Größen zusammen addieren:

Mit MongoDB 3.4 oder höher $concatArrays

Model.aggregate([ 
    { "$redact": { 
    "$cond": { 
     "if": { 
     "$gt": [ 
      { "$size": { 
      "$concatArrays": [ 
       { "$ifNull": [ "$organisers", [] ] }, 
       { "$ifNull": [ "$volunteers", [] ] }, 
       { "$ifNull"; [ "$participants", [] ] }, 
       { "$ifNull": [ "$mentors", [] ] } 
      ] 
      } }, 
      500 
     ]  
     }, 
     "then": "$$KEEP", 
     "else": "$$PRUNE" 
    } 
    }}, 
    { "$project": { "_id": 1 } } 
],function(err,results) { 

}) 

verwendet oder in früheren Versionen ohne diesen Operator

Model.aggregate([ 
    { "$redact": { 
    "$cond": { 
     "if": { 
     "$gt": [ 
      { "$add": [ 
      { "$size": { "$ifNull": [ "$organisers", [] ] } }, 
      { "$size": { "$ifNull": [ "$volunteers", [] ] } }, 
      { "$size": { "$ifNull": [ "$participants", [] ] } }, 
      { "$size": { "$ifNull": [ "$mentors", [] ] } } 
      ]}, 
      500 
     ]  
     }, 
     "then": "$$KEEP", 
     "else": "$$PRUNE" 
    } 
    }}, 
    { "$project": { "_id": 1 } } 
],function(err,results) { 

}) 

In beiden Vorgehensweisen verwenden Sie $redact als logischen Filter für die Dokumente in der Sammlung. Als nativer Operator ist dies der schnellste Weg, um diese Bedingung zu bearbeiten.

Intern ist nur das Argument $cond, das eine "ternäre" Operation (if/then/else) ist, um einen Wert auszuwerten und zurückzugeben. Also, wenn das Ergebnis der Bedingung zu "if" in true, "then" führt, ist die Aktion zu $$KEEP das Dokument oder alternativ "else" zu $$PRUNE das Dokument aus den Ergebnissen.

Die unterschiedlichen Ansätze auf Versionen basieren entweder:

  • $concatArrays um eine „große“ Array zu machen und senden Sie es $size

  • ist oder $size auf jedem Array verwenden und $add die Werte zu bekomme eine Summe.

Was gerade nur das _id Feld zurückkehrt, dann ist es eine einfache Sache, eine $project Stufe des Hinzufügens, wo wie gerade in regelmäßiger Abfrage Projektion, die Liste der Eigenschaften bietet zurückzukehren. In diesem Fall nur das _id Feld.

Sie könnten zuerst einige Vermutungen bezüglich der minimalen Array-Länge zur Basisabfrage mit einer $match hinzufügen, aber dies wäre eher eine Annahme als eine absolute Tatsache.


Für die Aufzeichnung können Sie genau das Gleiche mit der $where Klausel laufen, aber da dieser Operator verwendet Auswertung JavaScript anstatt nativ als die Aggregation Rahmenmaßnahmen umgesetzt werden, dann ist es eine erhebliche Auswirkung auf die Leistung machen dadurch, dass es langsamer läuft:

Model.find({ "$where": function() { 
    return [ 
    ...this.organisers, 
    ...this.volunteers, 
    ...this.participants, 
    ...this.mentors 
    ].length > 500 
}).select({ "_id": 1 }).exec(function(err,results) { 
}) 

Also während es „hübsch aussieht“ kann im Vergleich zur DSL Form einer Aggregation Pipeline-Struktur, ist die Leistungseinbuße nicht wirklich gelohnt.Sie sollten dies nur tun, wenn Ihre MongoDB-Version $redact als Operator hat, was vor MongoDB 2.6 wäre. In diesem Fall sollten Sie MongoDB wahrscheinlich auch aus anderen Gründen aktualisieren.

+0

Was erreicht der Operator "redact" hier? Ich kann den Rest verstehen! – bholagabbar

+0

@bholababbar Es gibt einen Link. Und ich habe die Erklärung tatsächlich hinzugefügt, während du tippst. –

+0

Nun, wenn ich nur eine Liste der Hackathon Ids 'ID' nur die gesamte Modelle abrufen wollte, wie würde diese Abfrage geändert werden? Wenn es eine 'find()' Abfrage wäre, würde ich etwas wie 'find ({id}, ... query) machen'; wäre es auch hier so? – bholagabbar

Verwandte Themen