Closest MongoDB match by properties

Let it say that I have a Users collection in MongoDB, the scheme of which looks like this:

{ name: String, sport: String, favoriteColor: String } 

And let's say that I passed values โ€‹โ€‹like this to match the user:

{ name: "Thomas", sport: "Tennis", favoriteColor:"blue" }

What I would like to do is combine the user with these properties. However, if the user has not returned, I would like to combine the user with these properties:

{sport: "Tennis", favoriteColor:"blue" }

And if no user has returned, I would like to combine the user with this property:

{ favoriteColor: "blue" }

Is it possible to do something similar in the same query with Mongo? I saw a $switch condition in Mongo that would match in case and then return immediately, but the problem is that I cannot access the document that it would receive in the then block. It looks like you can write lines there.

Any suggestions on how to accomplish what I'm looking for?

Is it best (and the only way) to just do a few User.find({...}) queries?

+5
source share
5 answers

This is a good example of using MongoDB text index:

First you need to create a text index in these fields:

 db.users.ensureIndex({ name: "text", sport: "text", favoriteColor: "text" }); 

Then you can search for the best match with $ text ", limited by the number that should be displayed:

 db.users.find( { $text: { $search: "Tennis blue Thomas" } } ).limit(10) 
+3
source

Try adding a rank to all documents with a weight factor in the aggregation pipeline and summarize the rank, $sort , to get the most consistent documents on top

  • name โ†’ 1
  • sport โ†’ 2
  • favoriteColor โ†’ 4

doing this to match favoriteColor will always have a higher weight and then sport and name or a combination of both

aggregate pipeline

 db.col.aggregate([ {$match : { $or : [ {"name" : {$eq :"Thomas"}}, {"sport" : {$eq : "Tennis"}}, {"favoriteColor" : {$eq : "blue"}} ] }}, {$addFields : { rank : {$sum : [ {$cond : [{$eq : ["$name", "Thomas"]}, 1, 0]}, {$cond : [{$eq : ["$sport", "Tennis"]}, 2, 0]}, {$cond : [{$eq : ["$favoriteColor", "blue"]}, 4, 0]} ]} }}, {$match : {rank :{$gt : 0}}}, {$sort : {rank : -1}} ]) 
+2
source

We hope that this request will satisfy your requirement, you can get the corresponding result in a single hit db. Just create a query in the aggregate pipeline

 db.collection.aggregate([ {$match : { $or : [ {"name" : {$eq :"Thomas"}}, {"sport" : {$eq : "Tennis"}}, {"favoriteColor" : {$eq : "blue"}} ] }}, {$addFields : { rank : {$sum : [ {$cond : [{$and:[{$eq : ["$name", "Thomas"]},{$eq : ["$sport", "Tennis"]},{$eq : ["$favoriteColor", "blue"]}] } , 1, 0]}, {$cond : [{$and:[{$eq : ["$name", "Thomas"]},{$eq : ["$sport", "Tennis"]}] } , 2, 0]}, {$cond : [{$and:[{$eq : ["$name", "Thomas"]}] } , 3, 0]}, ]} }}, {$group:{ _id:null, doc:{$push:'$$ROOT'}, rank:{$max:'$rank'} }}, {$unwind:'$doc'}, {$redact: { $cond: { if: { $eq: [ "$doc.rank", '$rank' ] }, then: "$$KEEP", else: "$$PRUNE" } }}, { $project:{ name:'$doc.name', sport:'$doc.sport', favoriteColor:'$doc.favoriteColor', }} ]) 
+2
source

Just create a query builder for $match pipe in the mongoDB aggregation pipeline or use it to search, create a JavaScript object variable and dynamically create your request.

 var query={}; if(name!=null){ query['name']={ '$eq': name}; } if(sport!=null){ query['sport']={ '$eq': sport}; } if(favoriteColor!=null){ query['favoriteColor']={ '$eq': favoriteColor}; } db.collection.find(query) 

It will give a precisely consistent result on a dynamic basis.

+2
source

Have you tried $or : https://docs.mongodb.com/manual/reference/operator/query/or/

I used it when I wanted to check if a username or email address exists.

+1
source

Source: https://habr.com/ru/post/1275421/


All Articles