Tengo una colección en MongoDB que contiene el historial de búsqueda de un usuario donde se almacena cada documento como:
"_id": "user1" searchHistory: { "product1": [ { "timestamp": 1623482432, "query": { "query": "chocolate", "qty": 2 } }, { "timestamp": 1623481234, "query": { "query": "lindor", "qty": 4 } }, ], "product2": [ { "timestamp": 1623473622, "query": { "query": "table", "qty": 1 } }, { "timestamp": 1623438232, "query": { "query": "ike", "qty": 1 } }, ] }Aquí _id del documento actúa como una clave externa para el documento de usuario en otra colección.
Tengo un backend ejecutándose en nodejs y esta función se usa para almacenar un nuevo historial de búsqueda en el registro.
exports.updateUserSearchCount = function (userId, productId, searchDetails) { let addToSetData = {} let key = `searchHistory.${productId}` addToSetData[key] = { "timestamp": new Date().getTime(), "query": searchDetails } return client.db("mydb").collection("userSearchHistory").updateOne({ "_id": userId }, { "$addToSet": addToSetData }, { upsert: true }, async (err, res) => { }) }Ahora, quiero obtener el historial de búsqueda de un usuario basado en consultas solo usando db.find().
Quiero algo como esto: db.find({"_id": "user1", "searchHistory.somewildcard.query": "some query"})
Necesito un comodín que reemplace a ".somewildcard". para buscar en todos los productos buscados.
Vi una sugerencia de que deberíamos almacenar documentos como:
"_id": "user1" searchHistory: [ { "key": "product1", "value": [ { "timestamp": 1623482432, "query": { "query": "chocolate", "qty": 2 } } ] } ]Sin embargo, si almaceno un documento como este, agregar el historial de búsqueda al documento existente se convierte en una tarea mareante y confusa.
¿Qué tengo que hacer?
Siempre es una mala idea guardar los valores que son claves, precisamente por esta razón por la que te enfrentas. Limita en gran medida la consulta de ese campo, obviamente, la compensación es que hace que las actualizaciones sean mucho más fáciles.
Personalmente, le recomiendo que no guarde estas búsquedas en forma anidada, esto le causará problemas de escala con bastante rapidez, suponiendo que estos campos estén indexados, comenzará a ver problemas de rendimiento cuando las matrices sean demasiado grandes (unos pocos cientos de búsquedas).
Así que mi recomendación personal es que lo guardes en una nueva colección así:
{ "user_id": "1", "key": "product1", "timestamp": 1623482432, "query": { "query": "chocolate", "qty": 2 } }Ahora, consultar a un usuario específico o un producto específico o incluso una subcadena de consulta es muy fácil de realizar mediante la creación de algunos índices básicos. una "actualización" en este caso sería simplemente insertar un nuevo documento que también es mucho más rápido.
Si aún prefiere mantener la estructura anidada, le recomiendo que cambie a la estructura recomendada que publicó, como mencionó, las actualizaciones se volverán un poco más tediosas, pero aún puede hacerlo con bastante facilidad usando arrayFilters para actualizar un elemento específico o simplemente usando $push para agregar una nueva búsqueda