Din lösning borde verkligen vara MongoDB-specifik, annars kommer du att göra dina beräkningar och eventuell matchning på klientsidan, och det kommer inte att vara bra för prestandan.
Så det du verkligen vill ha är naturligtvis ett sätt att ha den bearbetningen på serversidan:
db.products.aggregate([
// Match the documents that meet your conditions
{ "$match": {
"$or": [
{
"features": {
"$elemMatch": {
"key": "Screen Format",
"value": "16:9"
}
}
},
{
"features": {
"$elemMatch": {
"key" : "Weight in kg",
"value" : { "$gt": "5", "$lt": "8" }
}
}
},
]
}},
// Keep the document and a copy of the features array
{ "$project": {
"_id": {
"_id": "$_id",
"product_id": "$product_id",
"ean": "$ean",
"brand": "$brand",
"model": "$model",
"features": "$features"
},
"features": 1
}},
// Unwind the array
{ "$unwind": "$features" },
// Find the actual elements that match the conditions
{ "$match": {
"$or": [
{
"features.key": "Screen Format",
"features.value": "16:9"
},
{
"features.key" : "Weight in kg",
"features.value" : { "$gt": "5", "$lt": "8" }
},
]
}},
// Count those matched elements
{ "$group": {
"_id": "$_id",
"count": { "$sum": 1 }
}},
// Restore the document and divide the mated elements by the
// number of elements in the "or" condition
{ "$project": {
"_id": "$_id._id",
"product_id": "$_id.product_id",
"ean": "$_id.ean",
"brand": "$_id.brand",
"model": "$_id.model",
"features": "$_id.features",
"matched": { "$divide": [ "$count", 2 ] }
}},
// Sort by the matched percentage
{ "$sort": { "matched": -1 } }
])
Så som du vet "längden" på $or
villkor som tillämpas, då behöver du helt enkelt ta reda på hur många av elementen i "features"-arrayen som matchar dessa villkor. Så det är vad den andra $matchen i pipelinen handlar om.
När du har den räkningen dividerar du helt enkelt med antalet villkor som skickades in som din $or
. Det fina här är att du nu kan göra något användbart med det här som att sortera efter den relevansen och sedan till och med "page" resultatserversidan.
Naturligtvis om du vill ha ytterligare "kategorisering" av detta, behöver du bara lägga till ytterligare ett $project
steg till slutet av pipelinen:
{ "$project": {
"product_id": 1
"ean": 1
"brand": 1
"model": 1,
"features": 1,
"matched": 1,
"category": { "$cond": [
{ "$eq": [ "$matched", 1 ] },
"100",
{ "$cond": [
{ "$gte": [ "$matched", .7 ] },
"70-99",
{ "$cond": [
"$gte": [ "$matched", .4 ] },
"40-69",
"under 40"
]}
]}
]}
}}
Eller som något liknande. Men $cond
operatör kan hjälpa dig här.
Arkitekturen bör vara bra som du har den eftersom du kan ha ett sammansatt index på "nyckel" och "värde" för posterna i din feature-array och detta bör skalas bra för frågor.
Om du faktiskt behöver något mer än så, såsom fasetterad sökning och resultat, kan du naturligtvis titta på lösningar som Solr eller elastisk sökning. Men den fullständiga implementeringen av det skulle bli lite långdragen här.