Tengo dos colecciones:

user ( userID, liveID )
live ( liveID )

Quiero obtener todas las vidas con un recuento de cuántos usuarios tienen asociada la liveID correspondiente. Esto es simple, esto es lo que hice:

db.getCollection('live').aggregate([
        { $match: { /* whatever if needed */ }},
        { $lookup: {
            from: 'user',
            localField: 'liveID',
            foreignField: 'liveID',
            as: 'count'
        }},
        { $addFields: { 'count': { $size: '$count' }}}, // I do this since I don't want the results, just the count
    ]
);

Esta consulta es bastante rápida y en un conjunto de datos de 10,000 vidas y 10,000 usuarios toma aproximadamente 0.031 segundos.

Ahora, necesito filtrar los resultados y simplemente obtener vidas donde su valor count es mayor que cero. Intenté agregar una operación simple $ match en mi canalización como { $match: { 'count': { $gt : 0 }}} y aumenta significativamente el tiempo de operación hasta 1.91 segundos.

Pensé que probablemente estoy haciendo algo no óptimo aquí, intenté usar $ project , sin embargo, solo me permite modificar el elemento y no eliminarlo por completo del conjunto de datos final. También encontré algunos ejemplos utilizando las tuberías $ lookup , pero no pude crear una consulta que funcione.

¿Hay algo que me falta aquí?

0
Maurício Giordano 25 jun. 2020 a las 09:24

2 respuestas

En lugar de tener un $addFields para obtener el tamaño del campo de matriz count y luego $match para filtrar los documentos con un tamaño mayor que cero, puede combinar ambas etapas como una sola {{ X3}} etapa. El operador $ expr permite utilizar operadores de agregación con el Etapa $match (y también dentro del método find). Usando la $expr construye la etapa $match de la siguiente manera:

{ $match: { $expr: { $gt: [ { $size: "$count" }, 0 ] } } }

Esta etapa seguirá el $lookup en la tubería. Trabajar en etapas menores en una tubería es una buena práctica y mejora el rendimiento, especialmente cuando el número de documentos que se procesan es grande.

0
prasad_ 25 jun. 2020 a las 07:03

Dependiendo de cuántos live coincidan con su condición inicial, podría ser mejor encontrar los usuarios primero. Luego únete al live y combínalo más tarde

db.getCollection('user').aggregate([
  {
    $group: {
      _id: '$liveID'
    }
  },
  {
    $lookup: {
      from: 'live',
      localField: '_id',
      foreignField: 'liveID',
      as: 'live'
   }
},
{
  $unwind: '$live'
}, {
  $replaceRoot: { $newRoot: '$live' }
}, {
  $match: { /* whatever if needed */ }
}]);
0
thammada.ts 25 jun. 2020 a las 08:13