Запрос MongoDB / Mon goose: как получить разные наборы данных на основе значения поля - PullRequest
1 голос
/ 20 февраля 2020

Я использую nodejs с mon goose библиотеку для моего взаимодействия с mongoDB.

Я создаю запрос целевой страницы (например, страницу Netflix), и мне нужно получить ~ 15 результатов для каждой категории (например, «Комедия», «Ужасы», «Драма» ...).

Похоже, это не лучшее решение для отправки запроса для каждой "категории" и решения проблем с обратным вызовом, а также тяжелого запроса к базе данных для простой загрузки страницы ... как показано ниже:

const categories = ['horror','drama','comedy']
let counterCallback = 0
let allShows = []
categories.map(category =>{
    Show.find({category: category},{limit: 15}, (err, shows)=>{
       if(shows){ allShows.push(shows)}
       allShows++
       if(allShows === categories.length){ return res.json(allShows) }
    })
})

Возможно, я думал о том, чтобы сделать запрос $or, но я не могу ограничить число для каждого "или" s ...

const categories = ['horror','drama','comedy']
Show.find({
    $or:categories.map(category=> {return {category: category} })
},{limit: 10})

Как я могу добиться запроса, ограничивающего количество результатов по «категории»?

Спасибо

Ответы [ 2 ]

2 голосов
/ 20 февраля 2020

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

var categories = ['horror', 'comedy', 'drama']

Show.aggregate([
    /** This $match would help to  limit docs to particular categories, as each pipeline in facet stage has to iterate to all docs in collection for thrice as 3 categories given, So at least limiting docs to needed categories. */
    { $match: { category: { $in: categories } } }, 
    {
        $facet: {
            'horror': [{ $match: { category: 'horror' } }, { $limit: 1 }],
            'comedy': [{ $match: { category: 'comedy' } }, { $limit: 1 }],
            'drama': [{ $match: { category: 'drama' } }, { $limit: 1 }]
        }
    }])

Тест: MongoDB-Playground

В качестве альтернативы вы также можете достичь этого, используя $group:

Show.aggregate([
    { $match: { category: { $in: categories } } },
    { $group: { _id: '$category', shows: { $push: '$$ROOT' } } },
    { $project: { category: '$_id', _id: 0, shows: { $slice: ['$shows', 1] } } },
    /** Below two stages are optional  */
    { $group: { _id: '', data: { $push: '$$ROOT' } } },
    { $project: { _id: 0 } }
])

Тест: MongoDB-Playground

1 голос
/ 20 февраля 2020

Вы можете использовать платформу агрегации MongoDB с операцией $group.

Я предполагаю, что у вас MongoDB v4.2. Для более ранних версий вместо {$replaceWith:"$data"} используйте {$ReplaceRoot:{newRoot:"$data"}}

Show.aggregate([
  {
    $match: {
      category: {
        $in: [
          "horror",
          "comedy",
          "drama"
        ]
      }
    }
  },
  {
    $group: {
      _id: "$category",
      data: {
        $push: "$$ROOT"
      }
    }
  },
  {
    $addFields: {
      data: {
        $slice: [
          "$data",
          15
        ]
      }
    }
  },
  {
    $unwind: "$data"
  },
  {
    $replaceWith: "$data"
  }
]).exec((err, shows) => {
    if (err) throw err;
    console.log(shows);
})

MongoPlayground

...