2012-03-28 60 views
3

我与地理空间索引的一些猫鼬型号:猫鼬更新多个地理空间索引

var User = new Schema({ 
    "name" : String, 
    "location" : { 
    "id" : String, 
    "name" : String, 
    "loc" : { type : Array, index : '2d'} 
    } 
}); 

我试图更新是区域内的所有物品 - 例如:

User.update({ "location.loc" : { "$near" : [ -122.4192, 37.7793 ], "$maxDistance" : 0.4 } }, { "foo" : "bar" },{ "multi" : true }, function(err){ 
    console.log("done!"); 
}); 

但是,这似乎只更新前100个记录。看看这些文档,看起来在地理空间索引find上有一个原生的限制,当你没有设置限制时就适用。

(从docs使用限制()来指定点的最大数量返回(100默认限制适用,如果未指定)

这似乎也适用于更新,无论multi国旗,这是一个巨大的阻力。如果我申请一个更新,它仅更新第100

现在我能想到的解决这个问题的唯一办法是做这样的事情骇人听闻的:

Model.find({"location.loc" : { "$near" : [ -122.4192, 37.7793 ], "$maxDistance" : 0.4 } },{limit:0},function(err,results){ 
    var ids = results.map(function(r){ return r._id; }); 
    Model.update({"_id" : { $in : ids }},{"foo":"bar"},{multi:true},function(){ 
     console.log("I have enjoyed crippling your server."); 
    }); 
}); 

虽然我甚至不能完全确定这可以工作(并且可以通过仅选择_id进行轻度优化),但我真的很希望避免在内存中保留一系列ID,因为这个数字可能会变得非常大。

编辑: 以上的黑客甚至不工作,看起来像一个find{limit:0}仍返回100个结果。所以,在绝望和沮丧的行为中,我写了一个递归方法来通过id分页,然后返回它们,以便我可以使用上述方法进行更新。我在下面添加了该方法作为答案,但不接受它,希望有人能找到更好的方法。

这是mongo服务器核心的一个问题,据我所知,所以mongoose和node-mongodb-native不是怪罪。然而,这真的很愚蠢,因为地理空间索引是使用mongo而不是其他一些更强大的NoSQL存储的原因之一。

有没有办法做到这一点?即使在node-mongodb-native或mongo shell中,我似乎也无法找到设置更新限制的方法(或者在这种情况下,通过设置为0来移除)。

+0

这似乎是一个错误,我建议在http://jira.mongodb.org/browse/SERVER报告它(的内置100极限无意的后果)。 – kristina 2012-03-29 20:12:40

+0

@Jesse - 你有报告吗?如果是这样,请你提供jira问题的链接。 – UpTheCreek 2012-08-16 07:21:29

+0

我有一个类似的问题,暂时无法获取超过100个地理匹配(在读),但可以通过更新到3.0.2猫鼬修复它(从2.7.x,并不确切地知道当/如果它得到固定的)。 – Timm 2012-08-21 06:25:28

回答

0

我很想看到这个问题固定的,但我不能想出一个办法来设置更新的限制,并经过广泛的研究,这似乎并不可能。另外,问题中的黑客攻击甚至不起作用,我仍然只获得100条记录,其中find和limit设置为0

在此之前固定在蒙戈,这里就是我如何得到它周围的:(!!警告:UGLY HACKS AHEAD:!!)

var getIdsPaginated = function(query,batch,callback){ 
    // set a default batch if it isn't passed. 
    if(!callback){ 
    callback = batch; 
    batch = 10000; 
    } 
    // define our array and a find method we can call recursively. 
    var all = [], 
     find = function(skip){ 
     // skip defaults to 0 
     skip = skip || 0; 
     this.find(query,['_id'],{limit:batch,skip:skip},function(err,items){ 
      if(err){ 
      // if an error is thrown, call back with it and how far we got in the array. 
      callback(err,all); 
      } else if(items && items.length){ 
      // if we returned any items, grab their ids and put them in the 'all' array 
      var ids = items.map(function(i){ return i._id.toString(); }); 
      all = all.concat(ids); 
      // recurse 
      find.call(this,skip+batch); 
      } else { 
      // we have recursed and not returned any ids. This means we have them all. 
      callback(err,all); 
      } 
     }.bind(this)); 
     }; 
    // start the recursion 
    find.call(this); 
} 

此方法将返回_ids的巨型阵列。因为它们已经被索引,所以它实际上非常快,但它仍然会调用db多于必要的次数。当这个方法调用回来了,你可以用的ID的更新,像这样:

Model.update(ids,{'foo':'bar'},{multi:true},function(err){ console.log('hooray, more than 100 records updated.'); }); 

这不是解决这一问题的最优雅的方式,你可以调整它的基于预期设置批次效率结果,但显然只需要在没有限制的情况下在$ near查询中调用update(或者为此寻找)的能力确实会有所帮助。