任何「比較」或「選擇」,實際上是施加的實際邏輯或多或少主觀。但作爲一般原則,您始終可以考慮陣列中匹配索引的乘積以及文檔中存在的數組。例如:
var sample = ["A",2,6,8,34,90];
db.getCollection('source').aggregate([
{ "$match": { "my_list": { "$in": sample } } },
{ "$addFields": {
"score": {
"$add": [
{ "$cond": {
"if": {
"$eq": [
{ "$size": { "$setIntersection": [ "$my_list", sample ] }},
{ "$size": { "$literal": sample } }
]
},
"then": 100,
"else": 0
}},
{ "$sum": {
"$map": {
"input": "$my_list",
"as": "ml",
"in": {
"$multiply": [
{ "$indexOfArray": [
{ "$reverseArray": "$my_list" },
"$$ml"
]},
{ "$indexOfArray": [
{ "$reverseArray": { "$literal": sample } },
"$$ml"
]}
]
}
}
}}
]
}
}},
{ "$sort": { "score": -1 } }
])
會在順序返回的文件是這樣的:
/* 1 */
{
"_id" : 1.0,
"my_list" : [ "A", 2, 6, 8, 34, 90],
"score" : 155.0
}
/* 2 */
{
"_id" : 2.0,
"my_list" : ["A", "F", 2, 6, 19, 8, 90, 55],
"score" : 62.0
}
/* 3 */
{
"_id" : 3.0,
"my_list" : [ 90, 34, 8, 6, 3, "A"],
"score" : 15.0
}
的關鍵之處在於在使用$reverseArray
施加,從$indexOfArray
的值將是通過在匹配的索引產生「較大」從「第一個到最後一個」的順序(顛倒過來)給出了一個更大的「權重」,以匹配數組開始處的匹配,而不是那些朝向結尾的匹配。
當然,你應該考慮的事情像第二個文件實際上包含的比賽「最」,有更多的數組項將放一個「更大的」權重初始比賽比第一文件內。
從上面的"A"
在第二個文檔中得分高於第一個,因爲儘管兩個匹配的第一個位置都是"A"
,但數組的長度更長。但是也有一些影響,即"F"
是不匹配的,因此比它在後面的數組中具有更大的負面影響。最後一份文件中的"A"
同樣適用,在陣列末尾,匹配對整體重量幾乎沒有影響。
考慮到這個問題的計數器是添加一些邏輯來考慮「完全匹配」的情況,例如這裏的樣本和當前數組的$setIntersection
的$size
比較。這將調整分數以確保匹配所有提供的元素的內容實際得分高於具有較少位置匹配的文檔,但總體上具有更多元素。
隨着「分數」的到位,您可以過濾掉結果(即$limit
)或其他可以應用的邏輯,以便僅返回所需的實際結果。但第一步是計算一個「分數」的工作。
所以這一切都一般主觀什麼邏輯,其實就是一個「最接近的匹配」,但$reverseArray
和$indexOfArray
操作一般都是關鍵,把「更重」在之前的索引相匹配,而不是最後一次。
總的來說你正在尋找邏輯的「計算」。聚合框架有一些可用的操作符,但實際應用的操作符取決於您的最終實現。我只是展示了一些「邏輯上起作用」的東西,但更重視數組比較中的「早期匹配」而不是「後者匹配」,當然還有數組實際上相同的「最重量」。
注意:可以使用的$unwind
的includeArrayIndex
選項沒有上面使用的主要運營商早期版本的MongoDB來實現類似的邏輯。然而,該過程確實需要使用$unwind
來解構陣列,並且這會導致性能下降可能會否定操作的有效性。
實際上,「比較」是什麼意思?你想比較集合中的每個文檔與所有其他文檔嗎?或者您是否要求將提供的數組與文檔中實際存儲的數組進行比較?這些方法有很多不同的方法,因此您需要清楚您實際詢問的是哪種情況。 –
我修改了這個問題。我提供了一個數組,並將搜索包含類似數組的文檔的集合。 – danspants
迭代所有文檔並在代碼中使用某些邏輯來執行此操作,mongo未配置爲使用這些邏輯。你將不得不爲此設計算法。 –