为了“加权”响应,那么基本原则是您必须确定结果的哪些部分对您正在执行的搜索更重要,并且基本上按照结果的重要性顺序提供适当的分数,因为您的规则。
这实际上是一个 MongoDB 的东西,而不是一个外部编码的东西,因为您需要分析服务器上的结果,尤其是当您考虑诸如“分页”加权结果时有很多加权结果时。要在服务器上执行此操作,您需要 .aggregate() 方法。
在等待您的输入时,我已经有了自己的数据样本,但它仍然可以作为示例。考虑到这个初始样本。
{ "petsAllowed" : true, "rooms" : 5, "type" : "townhouse" }
{ "petsAllowed" : false, "rooms" : 4, "type" : "house" }
{ "petsAllowed" : true, "rooms" : 4, "type" : "townhouse" }
{ "petsAllowed" : false, "rooms" : 4, "type" : "townhouse" }
{ "petsAllowed" : true, "rooms" : 2, "type" : "townhouse" }
{ "petsAllowed" : true, "rooms" : 3, "type" : "townhouse" }
{ "petsAllowed" : true, "rooms" : 4, "type" : "house" }
所以这还包括一个“类型”,我们也将在匹配中“模糊”,而不仅仅是确定“精确”匹配。使用聚合管道并根据输入设置逻辑基本上是这样的:
var roomsWanted = 4,
exact = "townhouse",
types = [];
// Some logic to get the "fuzzy" values
var fuzzy = [/house/]
// Combine exact and fuzzy
types.push(exact);
fuzzy.forEach(function(fuzz) {
types.push(fuzz);
});
// Perform the query
db.houses.aggregate([
// Match items you want and exclude others
{ "$match": {
"type": { "$in": types },
"$or": [
{ "rooms": { "$gte": roomsWanted } },
{ "rooms": roomsWanted - 1 }
]
}},
// Calculate a score
{ "$project": {
"petsAllowed": 1,
"rooms": 1,
"type": 1,
"score": {
"$add": [
// Exact match is higher than the fuzzy ones
// Fuzzy ones score lower than other possible matches
{ "$cond": [
{ "$eq": [ "$type", "townhouse" ] },
20,
2
]},
// When petsAllowed is true you want a weight
{ "$cond": [
"$petsAllowed",
10,
0
]},
// Score depending on the roomsWanted
{ "$cond": [
{ "$eq": [ "$rooms", roomsWanted ] },
5,
{ "$cond": [
{ "$gt": [ "$rooms", roomsWanted ] },
4,
{ "$cond": [
{ "$eq": [ "$rooms", roomsWanted - 1 ] },
3,
0
]}
]}
]}
]
}
}},
{ "$sort": { "score": -1 } },
])
然后您得到的结果将按生成的“分数”排序,如下所示:
{ "petsAllowed" : true, "rooms" : 4, "type" : "townhouse", "score" : 35 }
{ "petsAllowed" : true, "rooms" : 5, "type" : "townhouse", "score" : 34 }
{ "petsAllowed" : true, "rooms" : 3, "type" : "townhouse", "score" : 33 }
{ "petsAllowed" : false, "rooms" : 4, "type" : "townhouse", "score" : 25 }
{ "petsAllowed" : true, "rooms" : 4, "type" : "house", "score" : 17 }
{ "petsAllowed" : false, "rooms" : 4, "type" : "house", "score" : 7 }
把它分解成这里发生的事情,第一件事是我自己的决定,我可能想要“类型”中包含“房子”的任何东西,以及所选类型的任何“精确匹配”。这是确定这一点的任意逻辑,但重点是我们将在此示例中同时考虑两者。
当然,搜索会过滤掉你真正不想要的任何东西,所以有一个$match 管道阶段可以做到这一点。 $in 运算符用于将“类型”与确切的“联排别墅”术语或可能的正则表达式匹配 /house/ 匹配。那是因为我也想要它,而你的里程可能会因你真正想做的事情而有所不同。
还有一个条件是寻找房间的数量。这里的一个任意决定是我会考虑任何有四个或更多房间的东西,因此**$gte** 条件。我还想考虑比要求的房间少一个的东西。再次武断的逻辑,但只是为了证明你在需要时做什么。
$match 完成“过滤”后,您将结果移至$project 阶段。此处的要点是您需要计算出的“分数”值,但您还必须指定所有在使用此管道阶段时要返回的字段。
在这里,您可以选择哪些“权重”适用于条件。 $add 运算符将“求和”作为其参数给出的结果,而这些结果又由 $cond 或“条件”运算符生成。
这是一个“三元”运算符,因为它评估逻辑“if”条件作为第一个参数,然后返回true 第二个参数或false 第三个参数。与任何三元组一样,当您想要测试不同的条件以“嵌套”false 参数中的运算符以便“流过”它们时。
一旦确定了“分数”,$sort 就会按照最大“分数”的顺序排列结果。
可以通过在管道末尾添加$skip 和$limit 管道阶段以传统形式实现分页,或者通过保留最后看到的值并排除更多涉及的“前向分页”来完成那些从结果中寻找“分数”$lte 看到的最后一个“分数”的人。这本身就是另一个主题,但这完全取决于哪种分页概念最适合您的应用程序。
当然,对于“petsAllowed”等一些逻辑,您只希望这些条件在实际对您想要的选择标准有效时计算权重。聚合管道语法和所有 MongoDB 查询语法的部分优点在于,无论语言实现如何,它基本上只是“数据结构”的表示。因此,您可以根据输入的需要“构建”管道阶段,就像代码中的任何数据结构一样。
这些是原则,但当然一切都是有代价的,“即时”计算这些权重不仅仅是一个可以在索引中查找值的简单查询。