Е, вашето решение наистина трябва да е специфично за MongoDB, в противен случай ще свършите да правите вашите изчисления и евентуално съпоставяне от страна на клиента, а това няма да е добре за производителността.
Така че, разбира се, това, което наистина искате, е начин да имате тази обработка от страна на сървъра:
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 } }
])
Както знаете "дължината" на $or
условие се прилага, тогава просто трябва да разберете колко от елементите в масива "характеристики" отговарят на тези условия. Така че това е второто $match в тръбопровода.
След като имате този брой, просто разделяте на броя на условията, които са били предадени като $or
. Красотата тук е, че сега можете да правите нещо полезно с това, като сортиране по тази уместност и след това дори да „стражирате“ от страната на сървъра с резултати.
Разбира се, ако искате допълнителна "категоризация" на това, всичко, което трябва да направите, е да добавите друг $project
етап до края на тръбопровода:
{ "$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"
]}
]}
]}
}}
Или като нещо подобно. Но $cond
операторът може да ви помогне тук.
Архитектурата трябва да е добра, тъй като можете да имате комбиниран индекс за „ключ“ и „стойност“ за записите във вашия масив от функции и това трябва да се мащабира добре за заявки.
Разбира се, ако всъщност имате нужда от нещо повече от това, като фасетно търсене и резултати, можете да разгледате решения като Solr или еластично търсене. Но пълното прилагане на това би било малко продължително за тук.