Welnu, uw oplossing zou echt MongoDB-specifiek moeten zijn, anders zult u uw berekeningen en mogelijke overeenkomsten aan de kant van de klant doen, en dat is niet goed voor de prestaties.
Dus wat je natuurlijk echt wilt, is een manier om die verwerking aan de serverkant te hebben:
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 } }
])
Dus zoals u de "lengte" kent van de $or
voorwaarde wordt toegepast, hoeft u alleen maar uit te zoeken hoeveel van de elementen in de array "features" aan die voorwaarden voldoen. Dus dat is waar de tweede $match in de pijplijn over gaat.
Zodra je dat aantal hebt, deel je gewoon door het aantal voorwaarden wat is doorgegeven als je $or
. Het mooie hiervan is dat je nu iets nuttigs hiermee kunt doen, zoals sorteren op die relevantie en dan zelfs de resultatenserverkant 'pagina'.
Natuurlijk, als je wat extra "categorisatie" hiervan wilt, hoef je alleen maar een ander $project
toe te voegen stap naar het einde van de pijplijn:
{ "$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"
]}
]}
]}
}}
Of als iets soortgelijks. Maar de $cond
operator kan je hier helpen.
De architectuur zou in orde moeten zijn zoals je die hebt, want je kunt een samengestelde index hebben op de "sleutel" en "waarde" voor de items in je feature-array en dit zou goed moeten schalen voor query's.
Als je echt iets meer nodig hebt dan dat, zoals facetzoeken en resultaten, kun je natuurlijk kijken naar oplossingen als Solr of elastisch zoeken. Maar de volledige implementatie daarvan zou hier wat lang duren.