2016-06-21 10 views
2

Ich habe ein Problem zu finden und Daten aus der Sammlung zu erhalten. Hier ist meine Sammlung DatenMongoDB Abfrage von dynamischen Feldern zu finden

/* 1 */ 
{ 
    "_id" : 1, 
    "name" : "sue", 
    "age" : 19, 
    "type" : 1, 
    "points" : { 
     "A" : { 
      "type" : "label", 
      "values" : "abc" 
     }, 
     "B" : { 
      "mandatory" : false, 
      "type" : "text" 
     }, 
     "C" : { 
      "mandatory" : false, 
      "type" : "text" 
     } 
    } 
} 

/* 2 */ 
{ 
    "_id" : 2, 
    "name" : "bob", 
    "age" : 42, 
    "type" : 1, 
    "points" : { 
     "B" : { 
      "type" : "label", 
      "values" : "" 
     }, 
     "C" : { 
      "mandatory" : false, 
      "type" : "text" 
     } 
    } 
} 

/* 3 */ 
{ 
    "_id" : 3, 
    "name" : "ahn", 
    "age" : 22, 
    "type" : 2, 
    "points" : { 
     "A" : { 
      "type" : "label", 
      "values" : "abc" 
     }, 
     "C" : { 
      "mandatory" : false, 
      "type" : "text" 
     } 
    } 
} 

/* 4 */ 
{ 
    "_id" : 4, 
    "name" : "xi", 
    "age" : 34, 
    "type" : 2, 
    "points" : { 
     "A" : { 
      "type" : "label", 
      "allowedValues" : "abc" 
     }, 
     "C" : { 
      "mandatory" : false, 
      "type" : "text" 
     } 
    } 
} 

/* 5 */ 
{ 
    "_id" : 5, 
    "name" : "xyz", 
    "age" : 23, 
    "type" : 2, 
    "points" : { 
     "B" : { 
      "mandatory" : false, 
      "type" : "text" 
     }, 
     "C" : { 
      "values" : "C", 
      "type" : "text" 
     } 
    } 
} 

/* 6 */ 
{ 
    "_id" : 6, 
    "name" : "abc", 
    "age" : 43, 
    "type" : 1, 
    "points" : { 
     "A" : { 
      "type" : "label", 
      "values" : "abc" 
     }, 
     "B" : { 
      "mandatory" : false, 
      "type" : "text" 
     } 
    } 
} 

ich alle Dokumente wollen die "points""type"="label" und "values"="" aus dem Feld haben.

Wie erreiche ich diese Liste mit find() in mongoDB? Hat jemand eine Idee dazu?

+0

Würdest du vorher wissen, was A, B oder C ist? – chridam

+0

Nein, das ist nicht behoben. Es könnte noch viel mehr geben. Es werden dynamische Felder hinzugefügt. – Meteor

+0

@chridam aber vorschlagen, aber ich bin neu in mongoDB sein. Es wäre also großartig, wenn Sie irgendwelche Lösungen haben, die ich direkt anwenden kann. – Meteor

Antwort

0

Wie bei dem aktuellen Design, würden Sie einen Mechanismus brauchen eine Liste aller dynamischen Schlüssel in der Sammlung zB var dynamic_keys = ["A", "B", "C"] zu bekommen, diese Liste analysieren eine $or Abfrage zu erstellen, die, wenn sie über Ihre letzte Anfrage an die Anwendung aussehen sollte im wesentlichen wie

db.collection.find({ 
    "$or": [ 
     { "points.A.type": "label", "points.A.values": "" }, 
     { "points.B.type": "label", "points.B.values": "" }, 
     { "points.C.type": "label", "points.C.values": "" } 
    ] 
}) 

der erste Betrieb der dynamischen Tasten Liste immer nur möglich durch ist Map-Reduce.

Ausführen des folgenden mapreduce Betrieb in Mongo Shell wird eine separate Temperatur Sammlung temp_collection_keys mit allen dynamischen Schlüssel wie die _id Werte genannt bevölkern:

mr = db.runCommand({ 
    "mapreduce": "collection", 
    "map": function() { 
     for (var key in this.points) { emit(key, null); } 
    }, 
    "reduce": function() { }, 
    "out": "temp_collection_keys" 
}) 

Um eine Liste aller dynamischen Schlüssel, laufen auf verschiedene die resultierende Sammlung:

db[mr.result].distinct("_id") 
["A", "B", "C"] 

nun die Liste oben angegeben, können Sie Ihre Abfrage durch die Schaffung eines objec zusammenstellen können t, dessen Eigenschaften in einer Schleife gesetzt werden. Normalerweise wird Ihr $or Dokument diese Struktur hat:

var orQuery = { 
    "$or": [ 
     { "points.A.type": "label", "points.A.values": "" }, 
     { "points.B.type": "label", "points.B.values": "" }, 
     { "points.C.type": "label", "points.C.values": "" } 
    ] 
}; 

So die oben aufgeführte Liste von Subdokument Tasten verwenden, können Sie dynamisch den über $ oder Array mit nativen map() Methode auf dem deutlichen Array Ergebnis angewandt JavaScript-Konstrukt:

var mr = db.runCommand({ 
    "mapreduce": "collection", 
    "map": function() { 
     for (var key in this.points) { emit(key, null); } 
    }, 
    "reduce": function() { }, 
    "out": "temp_collection_keys" 
}); 

var orArray = db[mr.result].distinct("_id").map(function (key){ 
    var obj = { }; 
    obj["points."+key+".type"] = "label"; 
    obj["points."+key+".values"] = ""; 
    return obj; 
}); 

db.collection.find({ "$or": orArray }); 

Beispielausgabe

{ 
    "_id" : 2, 
    "name" : "bob", 
    "age" : 42, 
    "type" : 1, 
    "points" : { 
     "B" : { 
      "type" : "label", 
      "values" : "" 
     }, 
     "C" : { 
      "mandatory" : false, 
      "type" : "text" 
     } 
    } 
}