使用MongoDB获取百分比匹配属性的百分比

时间:2018-02-15 07:40:58

标签: mongodb mongodb-query

我有一个用例,我需要输入一些属性列表,这些属性列表在mongodb中提供结果搜索,其中90%属性与所有数据匹配。 例如: 我有像

这样的数据
[{
    id: 1,
    properties: {
        'property1': 'value1',
        'property2': 'value2',
        'property3': 'value3',
        'property4': 'value4',
        'property5': 'value5'
    }
},
{
    id: 2,
    properties: {
        'property1': 'value1',
        'property2': 'value2',
        'property6': 'value6',
        'property7': 'value7',
        'property8': 'value8',
        'property9': 'value9'
    }
},
{
    id: 3,
    properties: {
        'property9': 'value9'
    }
}]

我想搜索几个属性,我正在寻找至少50%的匹配,至少1个属性应该匹配任何两个输入 输入查询

find
{
    'property3', 'value3',
    'property7', 'value7'
}

从上面的输入中,它与DB中的3个数据中的2个数据匹配。 可以用MongoDB写查询吗?

1 个答案:

答案 0 :(得分:1)

这是应该让你去的东西(你需要一个更新版本的MongoDB,但至少是v3.4.4):

db.collection.aggregate({
    $addFields: { // we add a helper field
        "propertiesAsArray": { // called "propertiesAsArray"
            $objectToArray: "$properties" // which will be the array representation of the "properties" field
        }
    }
}, {
    $addFields: {
        "matchRatio": { // the value we are looking for is...
            $divide: [ { // ...the ratio between...
                $size: { // ...the number of items...
                    $filter: {
                        "input": "$propertiesAsArray", // ...in our magic property array...
                        "as": "this",
                        "cond": { // ...that match any of our conditions...
                            $or: [
                                { $eq: [ "$$this", { "k": "property3", "v": "value3" } ] },
                                { $eq: [ "$$this", { "k": "property7", "v": "value7" } ] },
                                // ...of which we could have any number...
                            ] 
                        } 
                    }
                }
            }, 2 ] // ...and the number of properties in your query
        }
    }
}, {
    $facet: { // create two separate stages
        "totalNumberOfDocs": [{
            $count: "count" // one just calculates the total number of documents
        }],
        matchingDocs: [{ // and the second stage first filters out the non-matching documents
            $match: {
                "matchRatio": { $gte: 0.50 } // we only want documents with a match ratio >= 50%
            }
        }, {
            $count: "count" // and then counts the remaining ones
        }]
    }
}, {
    $project: { // final calculation of the ratio ("2 out of 3" in your example --> 66%)
        "percentage": {
            $divide: [
                { $arrayElemAt: [ "$matchingDocs.count", 0 ] },
                { $arrayElemAt: [ "$totalNumberOfDocs.count", 0 ] }
            ]
        }
    }
})

如果你只是在寻找匹配的文件并且不太关心66%的数字那么这应该有用(未经测试,因为我正在路上)。

db.collection.aggregate({
    $addFields: { // we add a helper field
        "propertiesAsArray": { // called "propertiesAsArray"
            $objectToArray: "$properties" // which will be the array representation of the "properties" field
        }
    }
}, {
    $addFields: {
        "matchRatio": { // the value we are looking for is...
            $divide: [ { // ...the ratio between...
                $size: { // ...the number of items...
                    $filter: {
                        "input": "$propertiesAsArray", // ...in our magic property array...
                        "as": "this",
                        "cond": { // ...that match any of our conditions...
                            $or: [
                                { $eq: [ "$$this", { "k": "property3", "v": "value3" } ] },
                                { $eq: [ "$$this", { "k": "property7", "v": "value7" } ] },
                                // ...of which we could have any number...
                            ] 
                        } 
                    }
                }
            }, 2 ] // ...and the number of properties in your query
        }
    }
}, {
    $match: {
        "matchRatio": { $gte: 0.50 } // we only want documents with a match ratio >= 50%
    }
})