Подтвердить что ты не робот

Mongoose - поиск поддокументов по критериям

Я только что застрял в этой проблеме. У меня две схемы Mongoose:

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

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

Вопрос: как получить все поддокументы (в данном случае, childrenSchema objects) из каждого родительского документа? Предположим, что у меня есть некоторые данные:

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

Я хотел бы получить - в одном запросе - все дети старше 18 лет. Возможно ли это? Каждый ответ будет оценен, спасибо!

4b9b3361

Ответ 1

Вы можете использовать $elemMatch как оператор запроса-прогноза в самых последних версиях MongoDB. Из оболочки манго:

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

Это фильтрует документы младших детей из массива children:

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

Как вы можете видеть, дети по-прежнему группируются внутри своих родительских документов. Запросы MongoDB возвращают документы из коллекций. Вы можете использовать метод агрегации $unwind, чтобы разделить их на отдельные документы:

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

Я повторяю предложение $match для производительности: первый раз через него исключаются родители с детьми no, возраст которых не менее 18 лет, поэтому $unwind рассматривает только полезные документы. Второй $match удаляет вывод $unwind, который не соответствует, а $project возвращает информацию о детях из поддокументов на верхний уровень.

Ответ 2

В Mongoose вы также можете использовать элегантную .populate() функцию следующим образом:

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