Mongoose can't recognize my 2dsphere index

I'm trying to add 2dSphere index for my field startLocation exists in tourSchema. Here how it looks below

   startLocation: {
      type: {
        type: String,
        default: 'Point',
        enum: ['Point']
      },
      coordinates: [Number],
      address: String,
      description: String
    }

And you can also see below what and how I've added indexes on this Schema

tourSchema.index({price:1,ratingsAverage:-1});
tourSchema.index({slug:1});
tourSchema.index({ startLocation: '2dsphere' });

Unfortunately Mongodb can't recognize startLocation index. Using Mongo Compass , I'm able to see all indexes that I've created except startLocation:'2dsphere'.

Here is the error that postman gives me below when I send request to getDistances method in controller:

{
    "status": "error",
    "error": {
        "operationTime": "6791492473605586945",
        "ok": 0,
        "errmsg": "$geoNear requires a 2d or 2dsphere index, but none were found",
        "code": 27,
        "codeName": "IndexNotFound",
        "$clusterTime": {
            "clusterTime": "6791492473605586945",
            "signature": {
                "hash": "4LYCSBslSoLAoqj93bLXmpubBxs=",
                "keyId": "6779443539857113090"
            }
        },
        "name": "MongoError",
        "statusCode": 500,
        "status": "error"
    },
    "message": "$geoNear requires a 2d or 2dsphere index, but none were found",
    "stack": "MongoError: $geoNear requires a 2d or 2dsphere index, but none were found\n    at Connection.<anonymous> (C:\\Users\\timuc\\Downloads\\starter\\starter\\node_modules\\mongodb-core\\lib\\connection\\pool.js:443:61)\n    at Connection.emit (events.js:223:5)\n    at processMessage (C:\\Users\\timuc\\Downloads\\starter\\starter\\node_modules\\mongodb-core\\lib\\connection\\connection.js:364:10)\n    at TLSSocket.<anonymous> (C:\\Users\\timuc\\Downloads\\starter\\starter\\node_modules\\mongodb-core\\lib\\connection\\connection.js:533:15)\n    at TLSSocket.emit (events.js:223:5)\n    at addChunk (_stream_readable.js:309:12)\n    at readableAddChunk (_stream_readable.js:290:11)\n    at TLSSocket.Readable.push (_stream_readable.js:224:10)\n    at TLSWrap.onStreamRead (internal/stream_base_commons.js:181:23)"
}

I tried to add point: '2dsphere' which was recognized by mongodb but I'm not satisfied. Because when I send request to method in controller that returns success but with empty array.

Here is the method which was triggered in controller:

exports.getDistances = catchAsync(async (req, res, next) => {
  const { latlng, unit } = req.params;
  const [lat, lng] = latlng.split(",");
  if (!lat || !lng) {
    new AppError( "Please provide latitude and longitude in the format lat,lng", 400);
  }

  const distances = await Tour.aggregate([
    {
      $geoNear: {
        near: {
          type: "Point",
          coordinates: [lng * 1, lat * 1]
        },
        distanceField: "distance"
      }
    }
  ]);

  res.status(200).json({
    status: "success",
    data: {
      data: distances
    }
  });
});

also from router you can see how I send the request URL below

tourRouter.route('/distances/:latlng/unit/:unit').get(tourController.getDistances);

Upvotes: 1

Views: 1119

Answers (1)

Kevin
Kevin

Reputation: 516

I strongly believe that you are not using the proper collection. This is working for MongoDB 4.2.

Creating the index:

db.location.createIndex({
    startLocation: "2dsphere"
})

Indexes of that collection:

db.location.getIndexes()
[{
        "v": 2,
        "key": {
            "_id": 1
        },
        "name": "_id_",
        "ns": "stackoverflow.location"
    }, {
        "v": 2,
        "key": {
            "startLocation": "2dsphere"
        },
        "name": "startLocation_2dsphere",
        "ns": "stackoverflow.location",
        "2dsphereIndexVersion": 3
    }
]

Inserting some data:

db.location.insert({
    startLocation: {
        type: "Point",
        coordinates: [40, 5],
        address: "Hellostreet 1",
        description: "Hello"
    }
})

Aggregate the collection:

db.location.aggregate([{
        $geoNear: {
            near: {
                type: 'Point',
                coordinates: [41, 6]
            },
            distanceField: 'distance'
        }
    }
])

The result:

{
    "_id" : ObjectId("5e404cdd13552bde0a0a9dc5"),
    "startLocation" : {
            "type" : "Point",
            "coordinates" : [
                    40,
                    5
            ],
            "address" : "Hellostreet 1",
            "description" : "Hello"
    },
    "distance" : 157065.62445348964
}

Upvotes: 1

Related Questions