Запрос MongoDB по справочному документу

У меня есть две схемы, определенные в мангусте следующим образом:

Модель: Артикул

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 набора результатов для следующих сценариев:

  1. Получить все статьи, содержащие «wordAbc» и/или «wordXyz» в выбранное слово, предпочтительное слово или синонимы.
  2. Получите все уникальные слова в выбранное слово, предпочтительное слово и синонимы во всех статьях в базе данных

Каким будет лучший/эффективный способ выполнения запроса с использованием мангуста?

Для первого результата я попробовал этот частичный запрос, но получил сообщение CastError,

Article.find({})
.populate( 'words', null, { 'details': {$in: ['wordAbc', 'wordXyz']}} )
.exec(function(err, docs) {});
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
0
0
54
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я думаю, что вы можете достичь обеих целей, используя конвейер агрегации.

  1. 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"}
    }
}])
  1. 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-й агрегации.

  1. $project : Нам нужны только слова, поэтому я сохранил поле слов всех статей и удалил все остальные ненужные поля из пайплайна.
  2. $unwind: нам нужно раскрутить массив слов, чтобы мы могли $lookwords.details из коллекции слов на следующем этапе конвейера
  3. $lookup: заполнить детали из коллекции слов.
  4. $unwind : Поскольку $lookup возвращает массив, нам нужно раскрутить его, чтобы сделать его объектом.
  5. $unwind : раскрутить words.details.synonyms, чтобы мы могли сгруппировать их и создать массив уникальных слов на следующем этапе конвейера. На этом этапе отдельные документы в конвейере агрегации будут выглядеть примерно так:

    {
        words : {
            selectedWord :"someword",
            details : {
                preferredWord : "otherword",
                synonym : "synonymword"
            }
        }
    }
    
  6. $project: нам нужно было сгладить структуру объекта. После этого этапа отдельный документ в пайплайне будет выглядеть так:

    {
         selectedWord :"someword",
         preferredWord : "otherword",
         synonym : "synonymword"
    }
    
  7. $group : объединить все selectedWord в один массив, preferredWord в один массив и синонимы в один массив, $addToSet используется для удаления повторяющихся объектов

  8. $project: объедините все 3 массива и создайте один массив уникальных слов.

Для получения подробной информации обо всех используемых операторах mongoDB прочитайте соответствующую документацию.

$setUnion документация

$addToSet документация

$проектная документация

$ раскрутить документацию

Документация по всем операторам конвейера агрегации mongodb

Я надеюсь, что это помогает вам

Спасибо Рави за пошаговую иллюстрацию. Это именно то, что я искал.

fean 14.03.2019 20:56

Одна вещь, которую нужно добавить: знак «$» необходимо удалить из строки $_id: «null», иначе код будет через MongoError: поле «$_id» должно быть объектом-аккумулятором.

fean 14.03.2019 21:02

Ах да, извините, это была ошибка, я отредактирую это прямо сейчас.

Ravi Shankar Bharti 15.03.2019 02:39

Ваши запросы работают нормально, когда значение выходит во всех запрошенных полях, selectedWord, Details, PreferredWord и синонимах. Но если какие-либо поля данных пусты, оба запроса 1 и 2 не включают объект. Как я могу сделать эти поля необязательными в запросе?

fean 25.03.2019 22:07

Например, допустимое значение «selectedWord» не отображается, если в «details», «preferredWord» или «synonyms» нет ссылки. Как я могу преодолеть это?

fean 25.03.2019 22:15

Вы также можете использовать preserveNullAndEmptyArrays:true с $unwind, чтобы сохранить пустые массивы. Я обновлю ответ соответственно.

Ravi Shankar Bharti 26.03.2019 06:39

Другие вопросы по теме