Mongodb: выберите первые N строк из каждой группы - PullRequest
11 голосов
/ 28 июня 2011

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

{
  'blog_id':xxx,
  'timestamp':xxx,
  'title':xxx,
  'content':xxx
}

Как следует из вопроса, есть ли способ выбрать, скажем, последние 3 записи для каждого блога?

Ответы [ 4 ]

15 голосов
/ 08 января 2017

Сначала необходимо отсортировать документы в коллекции по полям blog_id и timestamp, а затем создать исходную группу, которая создает массив исходных документов в порядке убывания. После этого вы можете нарезать массив с документами, чтобы вернуть первые 3 элемента.

Интуиция может следовать в этом примере:

db.entries.aggregate([
    { '$sort': { 'blog_id': 1, 'timestamp': -1 } }, 
    {       
        '$group': {
            '_id': '$blog_id',
            'docs': { '$push': '$$ROOT' },
        }
    },
    {
        '$project': {
            'top_three': { 
                '$slice': ['$docs', 3]
            }
        }
    }
])
2 голосов
/ 28 июня 2011

Единственный способ сделать это в базовом монго, если вы можете жить с двумя вещами:

  • Дополнительное поле в вашем въездном документе, назовем его «возраст»
  • Новая запись в блоге с дополнительным обновлением

Если так, вот как вы это делаете:

  1. После создания нового вступления выполните обычную вставку, а затем выполните это обновление, чтобы увеличить возраст всех сообщений (включая ту, которую вы только что добавили для этого блога):

    db.entries.update ({blog_id: BLOG_ID}, {age: {$ inc: 1}}, false, true)

  2. При запросе используйте следующий запрос, который вернет самые последние 3 записи для каждого блога:

    db.entries.find ({age: {$ lte: 3}, отметка времени: {$ gte: STARTOFMONTH, $ lt: ENDOFMONTH}}). Sort ({blog_id: 1, age: 1})

Обратите внимание, что это решение действительно безопасно для параллелизма (нет записей с одинаковым возрастом).

1 голос
/ 25 декабря 2011

Этот ответ, используя карту, уменьшенную на drcosta из другого вопроса, добился цели

В монго, как использовать карту, чтобы получить группу по порядку самых последних

mapper = function () {
  emit(this.category, {top:[this.score]});
}

reducer = function (key, values) {
  var scores = [];
  values.forEach(
    function (obj) {
      obj.top.forEach(
        function (score) {
          scores[scores.length] = score;
      });
  });
  scores.sort();
  scores.reverse();
  return {top:scores.slice(0, 3)};
}

function find_top_scores(categories) {
  var query = [];
  db.top_foos.find({_id:{$in:categories}}).forEach(
    function (topscores) {
      query[query.length] = {
        category:topscores._id,
        score:{$in:topscores.value.top}
      };
  });
  return db.foo.find({$or:query});
0 голосов
/ 28 июня 2011

Это возможно с группой (агрегация), но это создаст сканирование полной таблицы.

Вам действительно нужно ровно 3 или вы можете установить лимит ... например: максимум 3 сообщения за последнюю неделю / месяц?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...