Mongodb基于字段是否包含数组值作为子字符串来查询集合

时间:2015-04-21 14:47:22

标签: arrays regex mongodb

提前感谢任何帮助人员!所以,我有两个集合: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中的位置字段与B中的城市字段来查找居住在美国的人.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来实现它,但它实际上似乎只是一个班轮。我也在学习如何加入这两个系列。

1 个答案:

答案 0 :(得分:4)

这在声明中并不是非常简单,但它是可能的。如果您的搜索字词列表与问题中所述的一样短,您可以在一行中将其组合成如下的正则表达式:

 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())
});