У меня есть две схемы, определенные в мангусте следующим образом:
Модель: Артикул
var articleSchema = new mongoose.Schema({
sequenceId: String
title: String,
abstract: String,
authors: [String],
date: Date,
words: [{
selectedWord: String,
details: { type: Schema.Types.ObjectId, ref: 'Word' }
}],
otherTags: [String]
})
Модель: Слово
var wordSchema = new mongoose.Schema({
preferredWord: String,
synonyms: [String],
category: String
})
Теперь я пытаюсь получить 2 набора результатов для следующих сценариев:
Каким будет лучший/эффективный способ выполнения запроса с использованием мангуста?
Для первого результата я попробовал этот частичный запрос, но получил сообщение CastError,
Article.find({})
.populate( 'words', null, { 'details': {$in: ['wordAbc', 'wordXyz']}} )
.exec(function(err, docs) {});



Я думаю, что вы можете достичь обеих целей, используя конвейер агрегации.
- Get all the articles that have 'wordAbc' and/or 'wordXyz' in either selectedWord, preferredWord or synonyms
Сначала вам нужно будет заполнить все слова в поле details массива words, а затем сопоставить статьи на основе selectedWord, preferredWord или synonyms.
Этого можно добиться следующим образом:
Article.aggregate([{
$unwind : {
path :"$words",
preserveNullAndEmptyArrays :true
}
},{
$lookup : {
from : "words",
localField : "words.details",
foreignField : "_id",
as : "words.details"
}
},{
$unwind : {
path : "$words.details",
preserveNullAndEmptyArrays : true
}
},{
$match : {
$or : [{
"words.selectedWord" : {$in: ['wordAbc', 'wordXyz']}
},{
"words.details.preferredWord" : {$in: ['wordAbc', 'wordXyz']}
},{
"words.details.synonyms" : {$in: ['wordAbc', 'wordXyz']}
}]
}
},{
$group : {
_id : "$_id",
title : {$first : "$title"},
abstract : {$first : "$abstract"},
authors : {$first : "$authors"},
date : {$first : "$date"},
words: {$push : "$words"},
otherTags: {$first : "$otherTags"}
}
}])
- Get all the unique words in selectedWord, preferredWord and synonyms across all the articles in the database
В этом случае вам нужно будет unwindwords массив, а затем populatewords.details из words коллекции, а затем unwindsynonyms массив, чтобы мы могли создать набор selectedWord, preferredWord и synonyms по всем articles, а затем, наконец, сделать целый набор все уникальные слова на последнем этапе конвейера агрегации.
Этого можно добиться следующим образом:
Article.aggregate([{
$project : {
words : "$words"
}
},{
$unwind : "$words"
},{
$lookup : {
from : "words",
localField : "words.details",
foreignField : "_id",
as : "words.details"
}
},{
$unwind : "$words.details"
},{
$unwind : "$words.details.synonyms"
},{
$project : {
selectedWord : "$words.selectedWord",
preferredWord : "$words.details.preferredWord",
synonyms : "$words.details.synonyms"
}
},{
$group : {
_id : "null",
selectedWord : {$addToSet :"$selectedWord"},
preferredWord : {$addToSet :"$preferredWord"},
synonyms : {$addToSet :"$synonyms"}
}
},{
$project : {
commonWords : {$setUnion : ["$selectedWord","$preferredWord","$synonys"]}
}
}])
Объяснение 2-й агрегации.
$project : Нам нужны только слова, поэтому я сохранил поле слов всех статей и удалил все остальные ненужные поля из пайплайна.$unwind: нам нужно раскрутить массив слов, чтобы мы могли $lookwords.details из коллекции слов на следующем этапе конвейера$lookup: заполнить детали из коллекции слов.$unwind : Поскольку $lookup возвращает массив, нам нужно раскрутить его, чтобы сделать его объектом.$unwind : раскрутить words.details.synonyms, чтобы мы могли сгруппировать их и создать массив уникальных слов на следующем этапе конвейера. На этом этапе отдельные документы в конвейере агрегации будут выглядеть примерно так:
{
words : {
selectedWord :"someword",
details : {
preferredWord : "otherword",
synonym : "synonymword"
}
}
}
$project: нам нужно было сгладить структуру объекта. После этого этапа отдельный документ в пайплайне будет выглядеть так:
{
selectedWord :"someword",
preferredWord : "otherword",
synonym : "synonymword"
}
$group : объединить все selectedWord в один массив, preferredWord в один массив и синонимы в один массив, $addToSet используется для удаления повторяющихся объектов
$project: объедините все 3 массива и создайте один массив уникальных слов.
Для получения подробной информации обо всех используемых операторах mongoDB прочитайте соответствующую документацию.
Документация по всем операторам конвейера агрегации mongodb
Я надеюсь, что это помогает вам
Одна вещь, которую нужно добавить: знак «$» необходимо удалить из строки $_id: «null», иначе код будет через MongoError: поле «$_id» должно быть объектом-аккумулятором.
Ах да, извините, это была ошибка, я отредактирую это прямо сейчас.
Ваши запросы работают нормально, когда значение выходит во всех запрошенных полях, selectedWord, Details, PreferredWord и синонимах. Но если какие-либо поля данных пусты, оба запроса 1 и 2 не включают объект. Как я могу сделать эти поля необязательными в запросе?
Например, допустимое значение «selectedWord» не отображается, если в «details», «preferredWord» или «synonyms» нет ссылки. Как я могу преодолеть это?
Вы также можете использовать preserveNullAndEmptyArrays:true с $unwind, чтобы сохранить пустые массивы. Я обновлю ответ соответственно.
Спасибо Рави за пошаговую иллюстрацию. Это именно то, что я искал.