如何在$ geoNear之后填充子文档

我正在使用NodeJs和Mongoose,并build立一个function列表附近的交易。

Deal.db.db.command({ "geoNear": Deal.collection.name, "near": [23,67], "spherical": true, "distanceField": "dis" }, function (err, documents) { if (err) { return next(err); } console.log(documents); }); 

交易模式:

 var dealSchema = new mongoose.Schema({ title: String, merchant: { type: mongoose.Schema.Types.ObjectId, ref: Merchant, index: true } }); 

在这里,我得到所有交易和他们距离当前位置的距离。 内部交易模式我有一个商人作为参考对象。

如何使用每个返回的交易对象填充商家? 我是否需要遍历所有返回的交易对象并手动填充?

这实际上是有趣的。 当然,你不想真正做的是“潜入”本地驱动程序的一部分,虽然你可能可以在解决scheme2。这导致有几个方法去实现这个没有实际滚动自己的查询来匹配这个手动。

首先一点设置。 而不是重现你的数据集,我只是select了一些我之前testing过的东西。 原则是一样的,所以一个基本的设置:

 var mongoose = require('mongoose'), async = require('async'), Schema = mongoose.Schema; mongoose.connect('mongodb://localhost'); var infoSchema = new Schema({ "description": String }); var shapeSchema = new Schema({ "_id": String, "amenity": String, "shape": { "type": { "type": String }, "coordinates": [] }, "info": { "type": Schema.Types.ObjectId, "ref": "Info" } }); var Shape = mongoose.model( "Shape", shapeSchema ); var Info = mongoose.model( "Info", infoSchema ); 

本质上是一个模型与“地理”信息和另一个只参考我们想要填充的信息。 另外我懒惰的数据更改:

 { "_id" : "P1", "amenity" : "restaurant", "shape" : { "type" : "Point", "coordinates" : [ 2, 2 ] } } { "_id" : "P3", "amenity" : "police", "shape" : { "type" : "Point", "coordinates" : [ 4, 2 ] } } { "_id" : "P4", "amenity" : "police", "shape" : { "type" : "Point", "coordinates" : [ 4, 4 ] } } { "_id" : "P2", "amenity" : "restaurant", "shape" : { "type" : "Point", "coordinates" : [ 2, 4 ] }, "info" : ObjectId("539b90543249ff8d18e863fb") } 

所以有一件事我们可以期待填充。 事实certificate, $near查询非常简单,按照预期进行sorting:

 var query = Shape.find( { "shape": { "$near": { "$geometry": { "type": "Point", "coordinates": [ 2, 4 ] } } } } ); query.populate("info").exec(function(err,shapes) { if (err) throw err; console.log( shapes ); }); 

这只是一个调用$near操作符的标准.find() 。 这是MongoDB 2.6语法,所以就是这样。 但结果sorting正确,并按预期填充:

 [ { _id: 'P2', amenity: 'restaurant', info: { _id: 539b90543249ff8d18e863fb, description: 'Jamies Restaurant', __v: 0 }, shape: { type: 'Point', coordinates: [ 2, 4 ] } }, { _id: 'P4', amenity: 'police', info: null, shape: { type: 'Point', coordinates: [ 4, 4 ] } }, { _id: 'P1', amenity: 'restaurant', info: null, shape: { type: 'Point', coordinates: [ 2, 2 ] } }, { _id: 'P3', amenity: 'police', info: null, shape: { type: 'Point', coordinates: [ 4, 2 ] } } ] 

这是相当不错的,一个简单的方法来调用。 赶上? 令人遗憾的是,将操作符更改为$geoNear将球面几何考虑在内,开始出现错误。 所以,如果你想这样做,那么你不能像以前那样做事情。

另一种方法是,mongoose有一个支持.geoNear()函数。 但是就像db.command调用一样,这不会返回将接受.populate()文档或其他Modeltypes的对象。 解? 稍微玩一下输出:

 var query = Shape.geoNear({ "type": "Point", "coordinates": [ 2, 4 ] },{spherical: true},function(err,shapes) { if (err) throw err; shapes = shapes.map(function(x) { delete x.dis; var a = new Shape( x.obj ); return a; }); Shape.populate( shapes, { path: "info" }, function(err,docs) { if (err) throw err; console.log( docs ); }); 

所以这里返回的结果是一个原始对象的数组。 但是通过一些操作,你可以将它们转换成可以在模型类中调用的.populate()方法,如图所示。

结果当然是一样的,虽然现场秩序可能有点不同。 而且你不需要自己迭代查询。 这实际上就是所有这些.populate()实际上在做,但我认为我们可以同意使用.populate()方法至less看起来更干净,并且不会为此目的重新发明轮子。