¿Cuál es la mejor manera de encontrar visitantes únicos en función del ID de visitante único en estos datos? Estoy usando Mongoose en un entorno Nodejs/Express.
{ username: "jack", events: [ { eventType: "party", createdAt: "2022-01-23T10:26:11.214Z", visitorInfo: { visitorId: "87654321-0ebb-4238-8bf7-87654321" } }, { eventType: "party", createdAt: "2022-01-30T10:26:11.214Z", visitorInfo: { visitorId: "87654321-0ebb-4238-8bf7-87654321" } }, { eventType: "party", createdAt: "2022-01-29T10:26:11.214Z", visitorInfo: { visitorId: "12345678-0ebb-4238-8bf7-12345678" } }, { eventType: "party", createdAt: "2022-01-31T10:16:11.214Z", visitorInfo: { visitorId: "12345678-0ebb-4238-8bf7-12345678" } } ] }Lo que estoy intentando:
Event.aggregate([ { $match: "jack" }, { $unwind: "$events" }, { $match: { "events.eventType": "party" } }, { $group: { _id: "$events.visitorInfo.visitorId", count: { $sum: 1 }, }, }, ]);Esto da la frecuencia de identificadores de visitantes únicos, y creo que podría haber una manera de usar eso para obtener visitantes únicos, pero estoy tratando de encontrar una forma cada vez más rápida de encontrar la cantidad de visitantes únicos en función del identificador de visitante único antes de ir por el conejo. agujero.
lo que espero al final:
visitors: { totalVisitors: 4, uniqueVisitors: 2 }Agradezco cualquier ayuda u orientación. ¡Gracias!
¡One Way está usando map y lodash !
find({}) . const vistorsIdsList = result.map(_ => visitorInfo.visitorId) const vistors = { total: vistorsIdsList.length, uniq: lodash.uniq(vistorsIdsList).length }Creo que en realidad estás en el camino correcto. Solo necesita hacer un $reduce para mantener el total de totalVisitors antes $unwind . Y en la etapa final, haz otro $group para obtener el resultado esperado.
db.event.aggregate([ { "$match": { username: "jack" } }, { "$addFields": { "totalVisitors": { "$reduce": { "input": "$events", "initialValue": 0, "in": { "$cond": { "if": { $eq: [ "$$this.eventType", "party" ] }, "then": { $add: [ "$$value", 1 ] }, "else": "$$value" } } } } } }, { $unwind: "$events" }, { $match: { "events.eventType": "party" } }, { $group: { _id: "$events.visitorInfo.visitorId", count: { $sum: 1 }, totalVisitors: { $first: "$totalVisitors" } } }, { $group: { _id: null, count: { $first: "$count" }, totalVisitors: { $first: "$totalVisitors" } } } ])Aquí está el Mongo Playground para su referencia.
versión 1 (filtro):
En mi humilde opinión, esta parece ser la mejor versión, para obtener los mejores resultados, necesitará un índice en "nombre de usuario"
db.collection.aggregate([ { $match: { username: "jack" } }, { $project: { p: { $filter: { input: "$events", as: "item", cond: { $eq: [ "$$item.eventType", "party" ] } } } } }, { $unwind: "$p" }, { $group: { _id: "0", visitors: { $push: "$p.visitorInfo.visitorId" }, uniqueVisitors: { $addToSet: "$p.visitorInfo.visitorId" } } }, { $project: { _id: 0, visitorsCount: { $size: "$visitors" }, uniqueVisitorsCount: { $size: "$uniqueVisitors" } } } ])Explicado:
versión 2 (sin usar filtro - adecuado para el neumático sin atlas)
db.collection.aggregate([ { $match: { username: "jack" } }, { $unwind: "$events" }, { $match: { "events.eventType": "party" } }, { $group: { _id: "0", visitors: { $push: "$events.visitorInfo.visitorId" }, uniqueVisitors: { $addToSet: "$events.visitorInfo.visitorId" } } }, { $project: { _id: 0, visitorsCount: { $size: "$visitors" }, uniqueVisitorsCount: { $size: "$uniqueVisitors" } } } ])play (versión sin filtro adecuada para el neumático atlas free)