Группировать, подсчитывать и передавать отдельные результаты запроса mongodb - PullRequest
0 голосов
/ 10 апреля 2020

В mongodb, имея коллекцию с sessionId с и label с, я бы хотел сгруппировать по идентификатору сессии, где метка равна 'view_item' и завершено sh:

  • Получить количество групп sessionId.
  • Возможность потоковой передачи каждого sessionId потребителю (при условии, что у меня ограниченные ресурсы памяти и большое количество отдельных sessionId s)

Предположим, что в коллекции есть следующие документы:

{ "label" : "view_item", "sessionId" : "01e5dnnpsczgfq58rmp0cjtjm0" }
{ "label" : "view_category", "sessionId" : "01e5dnnpsczgfq58rmp0cjtjm0" }
{ "label" : "view_item", "sessionId" : "01e5dnnpsczgfq58rmp0cjtjm0" }
{ "label" : "view_item", "sessionId" : "01e5g7vzx5dh0mv8m6g1zbdrnj" }
{ "label" : "view_item", "sessionId" : "01e5g7vzx5dh0mv8m6g1zbdrnj" }
{ "label" : "view_category", "sessionId" : "01e5g7vzx5dh0mv8m6g1zbdrnj" }
{ "label" : "view_item", "sessionId" : "01e5g7vzx5dh0mv8m6g1zbdrnj" }

Ожидаемый результат будет примерно таким:

Получите results как-то и ...

result.count() // 2 (or some other way of getting the count)
await result.next() // { sessionId: '01e5dnnpsczgfq58rmp0cjtjm0' }
await result.next() // { sessionId: '01e5g7vzx5dh0mv8m6g1zbdrnj' }
await result.next() // null

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

На данный момент у меня есть:

const result = collection.aggregate([
  { $match: { label: 'view_item' } },
  { $group : { _id: { sessionId: '$sessionId' } } },
]);

await result.next() // { _id: { sessionId: '01e5g7vzx5dh0mv8m6g1zbdrnj' } }
await result.next() // { _id: { sessionId: '01e5dnnpsczgfq58rmp0cjtjm0' } }
await result.next() // null

и

const result = collection.aggregate([
  { $match: { label: 'view_item' } },
  { $group : { _id: { sessionId: '$sessionId' } } },
  { $facet: { count: [{ $count: 'count' }] } }
]);

await result.next() // { count: [ { count: 2 } ] }
await result.next() // null

Вопрос

Как два вышеупомянутых запроса можно объединить, чтобы надежно получить счетчик и результат с сгруппированным sessionId, который может быть передан в поток? (Я предполагаю, что любое решение, основанное на result.toArray().length, должно загружать весь результат в память, что исключено).

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

Спасибо!

1 Ответ

0 голосов
/ 10 апреля 2020

Если я четко понимаю ваши требования, вам нужно собрать все сеансы, которые были назначены каждому ярлыку, в один массив и считать, что сеансы

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

мы можем сделать что-то подобное

db.collection.aggregate([
  {
    $match: {} // if you need the 'View_Item' labels only, than add it here
  },
  {
    $group: {
      _id: "$label", // make the _id of the results is the label
      sessionsIds: { // array of sessions
        $push: "$sessionId"
      }
    }
  },
  {
    $project: { // use the $project as $size is available only in the $project stage
      _id: 1,
      sessionsIds: 1,
      sessionsCount: {
        $size: "$sessionsIds"
      }
    }
  }
])

, вы можете попробовать это здесь, в Mon go Playground

Обновление, если вам нужно получить количество уникальных идентификаторов сеансов и не дублировать массив sessionsIds, используйте $addToSet вместо $push


обновление 2 : если нам нужно сгруппировать идентификатор сессии и посчитать, сколько документов имеет этот идентификатор сессии, мы можем сделать что-то вроде

db.collection.aggregate([
  {
    $match: {} // if you need the 'View_Item' labels only, than add it here
  },
  {
    $group: {
      _id: "$sessionId",
      count: {
        $sum: 1
      }
    }
  }
])

это вернет результат

[
  {
    "_id": "01e5dnnpsczgfq58rmp0cjtjm0",
    "count": 3
  },
  {
    "_id": "01e5g7vzx5dh0mv8m6g1zbdrnj",
    "count": 4
  }
]

если вам нужно сделать _id результата объектом, а не ObjectId, мы могли бы сделать что-то вроде

db.collection.aggregate([
  {
    $match: {} // if you need the 'View_Item' labels only, than add it here
  },
  {
    $group: {
      _id: {
        sessionId: "$sessionId"
      },
      count: {
        $sum: 1
      }
    }
  }
])

, это приведет к

[
  {
    "_id": {
      "sessionId": "01e5dnnpsczgfq58rmp0cjtjm0"
    },
    "count": 3
  },
  {
    "_id": {
      "sessionId": "01e5g7vzx5dh0mv8m6g1zbdrnj"
    },
    "count": 4
  }
]

вы можете попробовать все это здесь Mongo_P layground 2

...