我正在使用NodeJs和Mongoose,并建立一个功能来列出附近的交易。
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
}
});
在这里,我获得所有优惠及其与当前位置的距离。 Inside Deal架构我有一个商家作为参考对象。
如何使用每个返回的Deal对象填充商家? 我是否需要遍历所有返回的Deal对象并手动填充?
答案 0 :(得分:3)
这实际上有点有趣。当然你不想真正做的是“深入”本机驱动程序部分,尽管你可能在解决方案2上。这导致有几种方法可以解决这个问题,而无需实际滚动自己的查询来手动匹配
首先进行一点设置。我没有复制你的数据集,而是选择了我之前测试过的东西。原则是相同的,所以基本设置:
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 );
基本上是一个带有“geo”信息的模型,另一个带有我们想要填充的一些信息。还有我懒惰的数据更改:
{
"_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")
}
因此,有一件事我们可以期待填充。事实证明, $near
查询非常简单,按预期排序:
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 );
});
这只是标准的.find()
,并且调用了 $near
运算符。这是MongoDB 2.6语法,所以就是这样。但结果排序正确并按预期填充:
[
{ _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
调用一样,这不会返回一个mongoose文档或其他接受.populate()
的Model类型对象。解?只需稍微播放一下输出:
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()
方法至少看起来更清洁,并且不会为此目的重新发明轮子。