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

时间:2014-07-21 02:27:31

标签: javascript node.js mongodb mongoose geospatial

我正在尝试使用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)
        });
});

控制台输出:

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: 

有人可以告知我的错误在哪里吗?

1 个答案:

答案 0 :(得分: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();
      });
    }

  ]
);

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

  userid: { type: [Number], required: true },

将字段定义为&#34;数组&#34;,在这种情况下,您似乎并不是故意的。如果你这样做,那么这样编写更有意义:

  userid: [{ type: Number, required: true }],

但是为了这个列表它只是显示为一个普通字段。 &#34;标签&#34; field作为一个数组是有意义的,并且已经以这种方式定义。

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

locationSchema.index({ 'loc': '2dsphere' });

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

  

...&#34; $ box运算符根据网格坐标返回文档,不查询GeoJSON形状。&#34;

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

      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 ]
              ]]
            }
          }
        }
      });

最后,&#34;点&#34;你正在寻找&#34;框外的谎言&#34;你指的是。 这是&#34;框&#34;你正在寻找&#34; Point&#34;显示在&#34;框内&#34;:

enter image description here

上面显示的列表更正了所有这些内容并提供了一个&#34; Point&#34;和&#34; Polygon&#34;表格实际上符合条件。尝试使用gejsonlint.com等网站来检查您正在使用的数据的有效性。