地理空间框查询 - Mongoose,Node.js MongoDB - 不返回任何结果

Ben*_*Ben 3 javascript geospatial mongoose mongodb node.js

我试图使用Mongoose运行Geo Box查询,但是没有得到任何结果.我已经构建了一个简化的测试用例:

var mongoose = require('mongoose');

// Schema definition
var locationSchema = mongoose.Schema({
    userid: { type : [Number], required: true},
    loc: {
        'type': {
            type: String,
            required: true,
            enum: ['Point', 'LineString', 'Polygon'],
            default: 'Point'
        },
        coordinates: []
    },
    tags:   { type : [String], index: true, required: true },
    create_date : {type: Date, "default": Date.now()}
});

locationSchema.index({ 'loc.coordinates': '2dsphere' });
var Location = mongoose.model('Location', locationSchema);

mongoose.connect('mongodb://localhost/test');

var chkin = new Location({
    userid: 1,
    loc: { type: 'Point', coordinates: [-122.424088, 37.529876] },
    tags:"foo"
});

chkin.save(function (err, locations) {
    console.log('SAVE err: ' + err)
    console.log('SAVE locations: ' + locations)
    console.log('');
    var query = Location.find(
        { "coordinates" :
            { "$geoWithin" :
                // <bottom left coordinates>  - <upper right coordinates> - long,lat
                { "$box" :[[-122.610168,37.598167], [-122.288818,37.845833]] }
            }
        }, function (err, docs) {
            console.log('FIND err: '+ err)
            console.log('FIND locations: '+docs)
        });
});
Run Code Online (Sandbox Code Playgroud)

控制台输出:

SAVE err: null
SAVE locations: { __v: 0,
  _id: 53cc7a3ea44a9bc70634fdc6,
  create_date: Sun Jul 20 2014 19:26:06 GMT-0700 (PDT),
  tags: [ 'foo' ],
  loc: { coordinates: [ -122.424088, 37.529876 ], type: 'Point' },
  userid: [ 1 ] }

FIND err: null
FIND locations: 
Run Code Online (Sandbox Code Playgroud)

任何人都可以建议我的错误在哪里?

Nei*_*unn 16

你在这里编写的内容有几个问题.最好看一下整个工作列表并打破它:

var async = require('async'),
    mongoose = require('mongoose'),
    Schema = mongoose.Schema;


var locationSchema = new Schema({
  userid: { type: Number, required: true },
  loc: {
    type: {
      type: "String",
      required: true,
      enum: ['Point', 'LineString', 'Polygon'],
      default: 'Point'
    },
    coordinates: [Number]
  },
  tags: [{ type: String, index: true, required: true }],
  create_date: { type: Date, default: Date.now }
});

locationSchema.index({ 'loc': '2dsphere' });
var Location = mongoose.model( 'Location', locationSchema );

mongoose.connect( 'mongodb://localhost/geotest' );

async.series(
  [

    function(callback) {
      Location.remove(function(err) {
        if (err) throw err;
        callback();
      });
    },

    function(callback) {
      var loc = new Location({
        userid: 1,
        loc: {
          type: 'Point',
          coordinates: [ -122.4481201171875, 37.71370177998719 ]
        },
        tags: "foo"
      });

      loc.save(function(err,loc) {
        if (err) throw err;
        console.log( "Location: %s", JSON.stringify( loc, undefined, 4 ) );
        callback();
      });
    },

    function(callback) {
      var query = Location.find({
        "loc": {
          "$geoWithin": {
            "$geometry": {
              "type": "Polygon",
              "coordinates": [[
                [ -122.610168, 37.598167 ],
                [ -122.288818, 37.598167 ],
                [ -122.288818, 37.845833 ],
                [ -122.610168, 37.845833 ],
                [ -122.610168, 37.598167 ]
              ]]
            }
          }
        }
      });
      query.exec(function(err,docs) {
        if (err) throw err;
        console.log( "Docs: %s", JSON.stringify( docs, undefined, 4 ) );
        callback();
      });
    }

  ]
);
Run Code Online (Sandbox Code Playgroud)

没有直接相关但似乎你不打算这样做是如何在你的模式中定义一些元素,如下所示:

  userid: { type: [Number], required: true },
Run Code Online (Sandbox Code Playgroud)

这将该字段定义为"数组",在这种情况下,您似乎并不意味着.如果你这样做,那么这样编写真的更有意义:

  userid: [{ type: Number, required: true }],
Run Code Online (Sandbox Code Playgroud)

但是为了这个列表它只是显示为一个普通的字段."tags"字段作为数组有意义并且已经以这种方式定义.

接下来要看的是索引定义.这可能是尝试不起作用的结果,但通常如果您在文档中的"loc"下定义GeoJSON结构,那么这就是您需要索引的字段.这可能与下一部分有关.

locationSchema.index({ 'loc': '2dsphere' });
Run Code Online (Sandbox Code Playgroud)

当您查询GeoJSON格式的对象时,$box无法使用辅助操作符:

..."$ box运算符根据网格坐标返回文档,不查询GeoJSON形状."

因此,当您实际使用GeoJSON时,必须指定为"Polygon"或"MultiPolygon"类型的边界,以匹配这些边界内的GeoJSON对象.无论如何,提供给$geoWithin的字段必须是保存索引的字段.您提供的"坐标"不是有效的顶级字段.根据您在"loc"或"loc.coordinates"上的索引字段:

      var query = Location.find({
        "loc": {
          "$geoWithin": {
            "$geometry": {
              "type": "Polygon",
              "coordinates": [[
                [ -122.610168, 37.598167 ],
                [ -122.288818, 37.598167 ],
                [ -122.288818, 37.845833 ],
                [ -122.610168, 37.845833 ],
                [ -122.610168, 37.598167 ]
              ]]
            }
          }
        }
      });
Run Code Online (Sandbox Code Playgroud)

最后,你正在寻找的"Point"位于你指定的"盒子"之外.这是你正在搜索的"盒子"和"盒子"外面显示的"点":

在此输入图像描述

上面显示的列表更正了所有这些内容并提供了"Point"和"Polygon"表单,实际上符合条件.尝试使用gejsonlint.com等网站检查您正在使用的数据的有效性.