一旦用户登录他/她的位置就会被报告。并继续每15分钟报告当前用户的位置。或至少在他们的会话结束之前。用Locate方法将用户位置读入数据库。它存储在与该特定用户关联的数据库中的位置数组中。这一切都很好。
将使用scan方法从数据库中读取用户位置。
我想知道如何围绕location.coordinates创建一个2dsphere。我知道我必须定位location.coordinates所以mongo知道将它视为2dsphere。所以我知道我必须使用User.ensureIndex({location:" 2dsphere"})。我的问题是:
1st)应该是User.ensureIndex(" location.coordinate":2dsphere)还是(" location":2dsphere)。这将是app.js的顶部。
第二)在我的扫描方法中,我试图创建逻辑和查询用户名匹配的文档除了在300米以外。所以最后我的问题是我的上一个Mongo查询结构正确
这是我的mongo Schema的样子:
var userSchema = mongoose.Schema({
username: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
},
email: {
type: String
},
location:
{
type: "Point",
coordinates: [Number, Number],
datetime: Date
},
points: {type:Number, default:10000},
imageUrl: {type:String, default:'/img/gravatar.jpg'}
});
这就是我的app.js的设置方式:
var User = require('../models/users.js');
var userController = {
locate: function (req, res) {
var data = req.body;
var date = new Date();
var username = req.user.username;
User.findOne({username:username}, function(err, user) {
if (err) return handleErr(err);
find = {
coordinates: [data.longitude, data.latitude],
datetime: date
};
user.location.push(find);
user.save();
});
},
scan: function (req, res) {
var date = new Date();
var twentyb4 = date.setMinutes(date.getMinutes - 15);
User.find({"datetime": {$gte: twentyb4}}, function (err, user) {
if (err) return handleErr(err);
for (var i = 0; i < user.length; i++) {
//return users other than current user
if(req.user.username !== user[i].username){
User.find({$and: [{username: user[i].username}, {$near: {$geometry: {type: "Point", coordinates: [ req.user.longitude, req.user.latiude ]}, $maxDistance: 300, $minDistance: 0}}]}, function(err, data){
if (err) return handleErr(err);
console.log(data.username);
});
}
}
});
};
因此,扫描功能最终要做的是查找数据库中的所有用户,不包括当前用户。然后它会过滤以获得在过去20分钟内登录的用户。然后我再次将其过滤掉,将其他用户的上次报告位置与当前用户的位置进行比较。
答案 0 :(得分:1)
您的架构错误,您需要解决此问题:
location:
{
type: "Point",
coordinates: [Number, Number],
datetime: Date
},
对此:
location: {
"type": { "type": String, "default": "Point" },
"coordinates": [Number, Number],
"datetime": Date
},
由于“类型”关键字混淆,“Point”不是mongoose数据类型。
您还需要为地理空间查询定义索引:
userSchema.index({ "location": "2dsphere" });
然后你的查询非常简单(这里你不需要$and
,因为所有的查询参数都已经是“和”条件了,你真的希望$nearSphere
这里有真实世界坐标: / p>
User.find({
"username": user[i].username,
"$nearSphere": {
"$geometry": {
"type": "Point",
"coordinates": [ parseFloat(req.user.longitude), parseFloat(req.user.latiude) ]
},
"$maxDistance": 300,
"$minDistance": 0
}
}, function(err, data) {
});
小心地注意那里的parseFloat
,因为我无法回想一下,如果Mongoose真的有聪明才能用这样的$nearSphere
查询来“输入”。
我还建议在这里“不要循环”,只是一次性获取当前用户名以外的所有用户。很简单,有一些预过滤和$in
运算符:
// Filter out username values only except for the current user
var otherUsers = user.map(function(u) {
return u.username
}).filter(function(u) { return u != req.user.username });
if ( otherUsers.length > 0 ) {
User.find({
"username": { "$in": otherUsers },
"$nearSphere": {
"$geometry": {
"type": "Point",
"coordinates": [ parseFloat(req.user.longitude), parseFloat(req.user.latiude) ]
},
"$maxDistance": 300,
"$minDistance": 0
}
}, function(err, data) {
});
} else {
// no-one else is within the time :(
}
现在,您在单个查询中测试了所有其他用户,因此您无需为循环结果和您真正需要的相关异步控制而烦恼。
答案 1 :(得分:0)
您只需要创建一次索引(不推荐使用ensureIndex,createIndex中存在相同的功能。由于您使用的是mongoose,只需在架构上定义索引,例如
userSchema.index({location: '2dsphere'});
您的查询几乎就在那里,这里的版本正确。
var geoJSONpoint = {
type: 'Point',
coordinates: [
req.user.longitude,
req.user.latitude
]
}
User.find({ username: user[i].username, location: { $near: { $geometry: geoJSONpoint, $maxDistance: 300 } } })
...
答案 2 :(得分:0)
继承人的工作解决方案:
我需要:
var userSchema = mongoose.Schema({
username: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
},
location:
{
type: { type: String, default: "Point" },
coordinates: [Number, Number],
datetime: Date
},
email: {
type: String
}
})
userSchema.index({ "location.coordinates": "2dsphere"}); //In my model
这是我在Node(服务器)中的控制器:
scan: function (req, res) {
var date = new Date();
var minusmin = date.setMinutes(date.getMinutes() - 20);
User.find({ "location.datetime": {$gte: minusmin}}, function (err, user) {
if (err) return handleErr(err);
for (var i = 0; i < user.length; i++) {
//return users other than current user
if(req.user.username !== user[i].username){
User.find({ username: user[i].username, "location.coordinates": { $nearSphere: { $geometry: { type: "Point", coordinates: [ req.user.location.coordinates[0], req.user.location.coordinates[1] ]}, $maxDistance: 300 } } }, function(err, data){
if (err) return handleErr(err);
console.log(data);
});
}
}
res.send(user);
});
}