MongoDB找到最接近的匹配

时间:2017-03-10 14:19:19

标签: mongodb

我想知道是否可以通过最接近的匹配来访问MongoDB中的文档。 例如我的搜索查询始终包含:
name
country
city

遵守规则:
1. name始终必须匹配 2.如果存在countrycity,则国家/地区的优先级更高 3.如果countrycity不匹配,请仅考虑此文档,如果它们具有默认值(例如,对于字符串:"")

示例查询:
name ="测试"
country =" USA"
city ="西雅图"

文件:

db.stuff.insert([
{
    name:"Test",
    country:"",
    city:"Seattle"
},{
    name:"Test3",
    country:"USA",
    city:"Seattle"
},{
    name:"Test",
    country:"USA",
    city:""
},{
    name:"Test",
    country:"Germany",
    city:"Seattle"
},{
    name:"Test",
    country:"USA",
    city:"Washington"
}
])

它应该返回第3个文件

谢谢!

2 个答案:

答案 0 :(得分:2)

考虑到不确定的要求和相互矛盾的更新,答案恰恰是一个解决问题的指导原则,它是否可行?"一部分。

应调整示例以满足期望。

db.stuff.aggregate([
    {$match: {name: "Test"}}, // <== the fields that should always match
    {$facet: {
        matchedBoth: [
            {$match: {country: "USA", city: "Seattle"}},  // <== bull's-eye
            {$addFields: {weight: 10}}                    // <== 10 stones
        ],
        matchedCity: [
            {$match: {country: "", city: "Seattle"}},   // <== the $match may need to be improved, see below 
            {$addFields: {weight: 5}}            
        ],
        matchedCountry: [
            {$match: {country: "USA", city: ""}},
            {$addFields: {weight: 0}}                  // <== weightless, yet still a match
        ]
        // add more rules here, if needed
    }},
    // get them together. Should list all rules from above  
    {$project: {doc: {$concatArrays: ["$matchedBoth", "$matchedCity", "$matchedCountry"]}}},
    {$unwind: "$doc"},              // <== split them apart
    {$sort: {"doc.weight": -1}},    // <== and order by weight, desc
    // reshape to retrieve documents in its original format 
    {$project: {_id: "$doc._id", name: "$doc.name", country: "$doc.country", city: "$doc.city"}}
]);

问题中解释最少的部分会影响我们如何构建方面。 e.g。

{$match: {country: "", city: "Seattle"}}

匹配国家/地区明确存在且为空字符串的所有文档。

很可能

{$match: {country: {$ne: "USA"}, city: "Seattle"}}

获取所有具有匹配名称和城市以及任何国家/地区,甚至

的文档

{$match: {$and: [{$or: [{country: null}, {country: ""}]}, {city: "Seattle"}]}}

答案 1 :(得分:0)

这是一个查询

db.collection.aggregate([
  {$match: {name:"Test"}},
  {$project: {
      name:"$name",
      country: "$country",
      city:"$city",
      countryMatch: {$cond: [{$eq:["$country", "USA"]}, true, false]},
      cityMatch: {$cond:[{$eq:["$city", "Seattle"]}, true, false]}
  }},
  {$match: {$and: [
      {$or:[{countryMatch:true},{country:""}]},
      {$or:[{cityMatch:true},{city:""}]}
      ]}},
  {$sort: {countryMatch:-1, cityMatch:-1}},
  {$project: {name:"$name", country:"$country", city:"$city"}}
])

说明:

首次匹配过滤掉与名称不匹配的文档(因为规则#1 - 名称应该匹配)。

下一个投影选择文档字段以及有关国家和城市匹配的一些信息。我们需要它来进一步过滤和排序文档。

第二场比赛过滤掉那些与国家和城市不匹配的文件,并且没有这些字段的默认值(规则#3)。

排序文档会在城市匹配之前移动国家/地区匹配,因为规则#2状态。最后 - 投影选择必填字段。

输出:

{
    _id: 3,
    name : "Test",
    country : "USA",
    city : ""
},
{
    _id: 1,
    name : "Test",
    country : "",
    city : "Seattle"
}

您可以限制查询结果以获得最接近的匹配。