Tengo una serie de objetos que se ven así:
{ type: 'foo', value : 2, hashedIdentifier : ASDZXC, createdAt : '2022-02-27T14:17:44.860+00:00' } Me gustaría insertarlos a granel en una colección de MongoDB. Mi lógica comercial exige que no se creen 2 objetos idénticos en un período de 7 días. Para eso, uso el campo hashedIdentifier para encontrar duplicados, donde createdAt es $gte "hace 7 días", filtro los duplicados de la matriz y luego inserto lo que queda en la matriz.
Estas son 2 consultas DB diferentes, y estoy buscando algo un poco más hermético y atómico.
Estaba mirando updateMany con upsert, pero no pude resolver esto.
¿Hay alguna manera de insertar todos los objetos de la matriz de forma masiva, insertando solo aquellos objetos que no entren en conflicto con la restricción anterior (identificador + rango createdAt)?
Una forma de hacerlo es usar una canalización de agregación con $merge . Por ejemplo:
db.collection.aggregate([ { $group: { _id: "$hashedIdentifier", latestExisting: { $max: "$createdAt" } } }, { $match: { _id: { $in: [ "ASDZXC", "TSSGKE", "SDFKAR" ] } } }, { $group: { _id: 0, existing: { $push: { hashedIdentifier: "$_id", latestExisting: "$latestExisting" } } } }, { $addFields: { newItems: [ { type: "foo", value: 2, hashedIdentifier: "ASDZXC", createdAt: ISODate("2022-03-06T14:18:44.860+00:00") }, { type: "bar", value: 3, hashedIdentifier: "TSSGKE", createdAt: ISODate("2022-03-06T15:17:44.860+00:00") }, { type: "newOne", value: 9, hashedIdentifier: "SDFKAR", createdAt: ISODate("2022-03-06T15:17:44.860+00:00") } ] } }, { $unwind: "$newItems" }, { $project: { existing: { $filter: { input: "$existing", as: "item", cond: { $eq: [ "$$item.hashedIdentifier", "$newItems.hashedIdentifier" ] } } }, newItems: 1, latestExisting: 1 } }, { $project: { existing: {$arrayElemAt: ["$existing", 0]}, newItem: "$newItems" } }, { $project: { delta: { $subtract: [ "$newItem.createdAt", "$existing.latestExisting" ] }, latestExisting: 1, newItem: 1 } }, { $match: { $or: [{ delta: {$gte: 604800000}}, {delta: null}] } }, { $replaceRoot: {newRoot: "$newItem"} }, { $merge: {into: "collection"} } ])Como puede ver en este ejemplo de patio de recreo.
Primero, agrupamos los documentos existentes por hashedIdentifier , ya que solo nos interesa la última fecha existente. Luego mantenemos los documentos relevantes que coinciden con los que probamos para insertar y los agrupamos en un solo documento. El siguiente paso es agregar todos los elementos nuevos usando $addFields y $unwind , para que sean documentos separados. Ahora solo tenemos que hacer coincidir para cada elemento nuevo, el elemento existente si hay alguno, y probar la condición de diferencia de tiempo (604800000 ms). Los documentos que coinciden con esta condición se pueden $merge de nuevo en la colección como nuevos documentos validados.