it-swarm.com.de

Mungo - Auffinden von Filialdokumenten nach Kriterien

Ich habe mich gerade mit diesem Problem beschäftigt. Ich habe zwei Mongoose-Schemata:

var childrenSchema = mongoose.Schema({
    name: {
        type: String
    },
    age: {
        type: Number,
        min: 0
    }
});

var parentSchema = mongoose.Schema({
    name : {
        type: String
    },
    children: [childrenSchema]
});

Die Frage ist, wie alle Filialdokumente (in diesem Fall childrenSchema Objekte) aus jedem übergeordneten Dokument abgerufen werden können. Nehmen wir an, ich habe einige Daten:

var parents = [
    { name: "John Smith",
    children: [
        { name: "Peter", age: 2 }, { name: "Margaret", age: 20 }
    ]},
    { name: "Another Smith",
    children: [
        { name: "Martha", age: 10 }, { name: "John", age: 22 }
    ]}
];

Ich möchte - in einer einzigen Abfrage - alle Kinder ab 18 Jahren abrufen. Ist das möglich? Jede Antwort wird geschätzt, danke!

30
Kuba T

In den neuesten MongoDB-Versionen können Sie $elemMatch Als Abfrageprojektionsoperator verwenden. Aus der Mongo Shell:

db.parents.find(
    {'children.age': {$gte: 18}},
    {children:{$elemMatch:{age: {$gte: 18}}}})

Dies filtert Dokumente jüngerer Kinder aus dem Array children heraus:

{ "_id" : ..., "children" : [ { "name" : "Margaret", "age" : 20 } ] }
{ "_id" : ..., "children" : [ { "name" : "John", "age" : 22 } ] }

Wie Sie sehen, sind Kinder immer noch in ihren übergeordneten Dokumenten gruppiert. MongoDB-Abfragen geben Dokumente aus Sammlungen zurück. Sie können die Methode $unwind Des Aggregationsframeworks verwenden, um sie in separate Dokumente aufzuteilen:

> db.parents.aggregate({
    $match: {'children.age': {$gte: 18}}
}, {
    $unwind: '$children'
}, {
    $match: {'children.age': {$gte: 18}}
}, {
    $project: {
        name: '$children.name',
        age:'$children.age'
    }
})
{
    "result" : [
        {
            "_id" : ObjectId("51a7bf04dacca8ba98434eb5"),
            "name" : "Margaret",
            "age" : 20
        },
        {
            "_id" : ObjectId("51a7bf04dacca8ba98434eb6"),
            "name" : "John",
            "age" : 22
        }
    ],
    "ok" : 1
}

Ich wiederhole die $match - Klausel für die Leistung: Beim ersten Mal werden Eltern mit nein Kindern im Alter von mindestens 18 Jahren eliminiert, sodass im $unwind Nur nützliche Dokumente berücksichtigt werden. Der zweite $match Entfernt $unwind - Ausgaben, die nicht übereinstimmen, und der $project Hebt Kinderinformationen von Filialdokumenten auf die oberste Ebene.

43

In Mongoose können Sie auch die elegante Funktion .populate() wie folgt verwenden:

parents
.find({})
.populate({
  path: 'children',
  match: { age: { $gte: 18 }},
  select: 'name age -_id'
})
.exec()
19
AbdelHady

Die Antwort von A. Jesse Jiryu Davis wirkt wie ein Zauber, aber für spätere Versionen von Mongoose (Mongoose 5.x) erhalten wir den Fehler:

Mongoose 5.x erlaubt nicht, eine Spreizung von Operatoren an Model.aggregate() zu übergeben. Anstelle von Model.aggregate({ $match }, { $skip }), mache Model.aggregate([{ $match }, { $skip }])

Der Code wäre also einfach jetzt:

> db.parents.aggregate([{
    $match: {'children.age': {$gte: 18}}
}, {
    $unwind: '$children'
}, {
    $match: {'children.age': {$gte: 18}}
}, {
    $project: {
        name: '$children.name',
        age:'$children.age'
    }
}])
{
    "result" : [
        {
            "_id" : ObjectId("51a7bf04dacca8ba98434eb5"),
            "name" : "Margaret",
            "age" : 20
        },
        {
            "_id" : ObjectId("51a7bf04dacca8ba98434eb6"),
            "name" : "John",
            "age" : 22
        }
    ],
    "ok" : 1
}

(Beachten Sie die Array-Klammern um die Abfragen)

Hoffe das hilft jemandem!

0
cjwiseman11