【问题标题】:Mongodb query a collection based on if the field contains an array value as substringMongodb根据字段是否包含数组值作为子字符串来查询集合
【发布时间】:2015-04-21 14:47:22
【问题描述】:

提前感谢大家的帮助!所以,我有两个集合:AB

A是个人信息的集合:

{
  "_id": "3453hkj54h5k34j5hkjh"  
  "location": "New York, U.S.",  
  "first-name": "Archer",  
  "last-name": "Vice",  
  "industry": "intelligence"
},
{
  "_id": "3453hkj5sdfdddjh",    
  "location": "London, UK",    
  "first-name": "Harry",    
  "last-name": "Potter",    
  "industry": "security"
},
{
  "_id": "345dfdf5sdfdddjh",
  "location": "D.C., US",
  "first-name": "Obama",  
  "last-name": "Barack",  
  "industry": "president"
}   

B是美国位置信息的集合:

{
  "_id": "998sdfdsfhejf",  
  "city": "New York",    
  "zip": "10122",  
  "state": "NY",  
  "lat": 40.749,  
  "longt": -73.9885
},  
{
  "_id": "998sdfsdfdsfhejf",  
  "city": "D.C."  
  "zip": "20500",  
  "state": "DC",  
  "lat": 38.8951,  
  "longt": -77.0369
}  

我通过比较 A 中的 location 字段和 B 中的 city 字段来找出谁住在美国。B 应该是 A 的子字符串,因为 A 通常带有州或国家/地区信息。

我已经通过以下方式将 B 转换为数组:

var f = db.collection.find(), n = [];
for (var i = 0; i < f.length(); i++) n.push(f[i]['field']);

现在 B 是var n=["D.C.", "New York"]

我知道如何检查数组中是否有东西。你这样做:

db.database.find({
   field: 
      { 
         $in: array 
      } 
   }); 

要检查子字符串,请执行以下操作:

db.database.find({A: /substring/ });

db.database.find({A: {$regex: 'substring'}});

预期结果是

{
  "_id": "3453hkj54h5k34j5hkjh",    
  "location": "New York, U.S.",   
  "first-name": "Archer",  
  "last-name": "Vice",  
  "industry": "intelligence"
},
{
  "_id": "345dfdf5sdfdddjh",
  "location": "D.C., US",  
  "first-name": "Obama",  
  "last-name": "Barack",  
  "industry": "President"
}   

"D.C., US" 包含子字符串"D.C.",它是数组n=["D.C.", "New York"] 中的一个值。

我知道我可以通过 mapreduce 做到这一点,但它实际上似乎只是一个单行。我也在学习如何加入这两个集合。

【问题讨论】:

  • 那么target 现在总是一个数组吗?
  • 不,这只是一个字段,抱歉不清楚。我会稍微修改一下帖子。
  • 不是很清楚你有什么和你想要什么。 B 是脚本中的数组还是某处的字段还是集合。另外,你为什么要调用你的集合 A 和 B,然后在测试集合中查询一个名为 A 的字段?
  • 你能给我们看一份完整的文件吗?
  • B 是一个集合,但它被我转换为一个数组。我只用它作为一个清单。如果您有兴趣,我会向您展示完整的文档。

标签: arrays regex mongodb


【解决方案1】:

这在语句中不是超级简单的,但它是可能的。如果您的搜索词列表与您在问题中所述的一样短,您可以在一行中将其组合成一个正则表达式,如下所示:

 db.test.find({location: {$regex: new RegExp(n.join('|'))}})

如果列表不是太长。如果正则表达式太复杂,它会很慢。如果它很短,您可以学习课程,那么您也可以逐字写出 RegExp。

n 是在 shell 中定义的,就像您在问题中一样。我在这里使用:

var n = ["D.C.", "New York"];

这将给出以下结果:

{ "_id" : "3453hkj54h5k34j5hkjh", "location" : "New York, U.S.", "first-name" : "Archer", "last-name" : "Vice", "industry" : "intelligence" }
{ "_id" : "345dfdf5sdfdddjh", "location" : "D.C., US", "first-name" : "Obama", "last-name" : "Barack", "industry" : "president" }

编辑

如果您的列表太长,可以使用以下方法加入:

n.reduce(function (lst, d) {
    var res = db.test.find({location: {$regex: d}}).toArray();
    Array.prototype.push.apply(lst, res); 
    return lst;
}, []);

它遍历列表中的所有条目并找到匹配的条目并将所有结果添加到一个新列表中。

如果您愿意,可以将它们插入到新集合中,以避免将它们全部保存在内存中。您也可以直接使用搜索,而不是将集合 B 中的结果提取到列表中。这在内存方面也应该更好。

这会将结果保存到集合名称test_result(在搜索中使用集合 A 和 B):

db.B.find().forEach(function (d) { 
    db.test_result.insert(db.A.find({location: {$regex: d.city}}).toArray())
});

【讨论】:

  • 非常感谢,但不幸的是它没有那么短,我把我们所有的城市都放在了那里,其中有 18691 个,所以有点复杂。我希望这样做,而不是简单地查询,我只是将它们输出到另一个集合。我正在进行的代码是这样的: for (var i=0; i
  • 你应该真正考虑你的目标是什么。正则表达式搜索 18691 项长列表中的所有术语有点狡猾。这不是您真正要求的简单陈述中所做的事情。使用 mongo 进行这样的模糊连接并不是最佳的,而且 mongo 开箱即用也不支持。然而,你可以用一些 js 魔法来实现它。
  • 目标是过滤掉所有不在美国的人。我最初想使用 Hadoop(mongodb 连接器)进行设置,使用 hive 进行查询,但没有成功。使用 mongodb 和 JavaScript 是 B 计划,C 计划是将所有内容转储到 MySQL。这是一个学校项目。非常感谢!我回家后会测试它。
  • 您好,我可以理解您返回光标的第二个脚本。但是,我很难理解最后一个是如何工作的。它给了我错误消息 $regex has to be a string.
  • 对不起。忘记字段名称city。它只是循环第一个查询的结果,并使用每个条目来查询第二个集合,并将每个结果插入到一个新集合中。
猜你喜欢
  • 2018-07-24
  • 2016-01-31
  • 2017-04-20
  • 2021-12-14
  • 2013-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多