2017-10-31 4 views
1

Wenn ich den folgenden Code ausführen (ein größeres Beispiel, auf das Wesentliche eingekocht)Abfrage beschwert sich über 2dsphere-Index fehlt, aber es ist da

var mongoose = require("mongoose"); 

var LocationSchema = new mongoose.Schema({ 
    userName: String, 
    loc: { 
    'type': { type: String, enum: "Point", default: "Point" }, 
    coordinates: { type: [Number] } 
    } 
}) 
LocationSchema.index({ category: 1, loc: "2dsphere" }); 
var Location = mongoose.model("location", LocationSchema); 
var mongoDB = 'mongodb://user1:[email protected]:42417/locationdemo'; 
mongoose.Promise = global.Promise; 
mongoose.connect(mongoDB, { useMongoClient: true }); 

var testUser = Location({ 
    userName: "Tester", 
    loc: { coordinates: [12.44, 55.69] } 
}); 
testUser.save(function (err) { 
    if (err) { 
    return console.log("UPPPPs: " + err); 
    } 
    console.log("User Saved, Try to find him:"); 

    let query = Location.find({ 
    loc: 
    { 
     $near: 
     { 
     $geometry: 
     { 
      type: "Point", 
      coordinates: [12.50, 55.71] 
     }, 
     $maxDistance: 600000 
     } 
    } 
    }) 
    query.exec(function (err, docs) { 
    if (err) { 
     return console.log("Err: " + err); 
    } 
    console.log("Found: " + JSON.stringify(docs)) 
    }) 
}); 

ich diesen Fehler:

Err: MongoError: error processing query: ns=locationdemo.locationsTree: GEONEAR field=loc maxdist=600000 isNearSphere=0 Sort: {} Proj: {} planner returned error: unable to find index for $geoNear query

Aber der Index ist da (siehe Zeile 10) und der Screenshot von mlab unten. Was mache ich falsch ?: enter image description here

+0

Gibt es etwas in der mitgelieferten Antwort, die Sie glaubt nicht, Ihre Frage zu beantworten? Wenn ja, dann kommentieren Sie bitte die Antwort, um zu klären, was genau adressiert werden muss, was nicht der Fall ist. Wenn es tatsächlich die Frage beantwortet, die Sie gestellt haben, dann beachten Sie bitte [Akzeptieren Sie Ihre Antworten] (https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work) zu den Fragen, die Sie stellen fragen Sie –

Antwort

1

Sie brechen eine Regel, wie Sie einen Index im Allgemeinen verwenden können. Es stimmt zwar, dass es einen "2dsphere" -Index gibt, der die "erste" Eigenschaft in einem zusammengesetzten Index ist, aber es ist sehr wichtig, dass Ihre "Abfragen" tatsächlich die erste Eigenschaft adressieren, damit der Index ausgewählt wird .

Dies ist in Prefixes aus dem Handbuch für zusammengesetzte Indizes abgedeckt. In Auszug:

{ "item": 1, "location": 1, "stock": 1 }

The index has the following index prefixes:

  • { item: 1 }
  • { item: 1, location: 1 }

For a compound index, MongoDB can use the index to support queries on the index prefixes. As such, MongoDB can use the index for queries on the following fields:

  • the item field,
  • the item field and the location field,
  • the item field and the location field and the stock field.

However, MongoDB cannot use the index to support queries that include the following fields since without the item field, none of the listed fields correspond to a prefix index:

  • the location field,
  • the stock field, or
  • the location and stock fields.

Weil Ihre Abfrage "loc"erste verweist und nicht "category" enthält, wird der Index nicht erhalten ausgewählt und MongoDB gibt den Fehler. Um den von Ihnen definierten Index zu verwenden, müssen Sie auch "category" abfragen. Änderung Ihren Eintrag:

var mongoose = require("mongoose"); 

mongoose.set('debug',true); 

var LocationSchema = new mongoose.Schema({ 
    userName: String, 
    category: Number, 
    loc: { 
    'type': { type: String, enum: "Point", default: "Point" }, 
    coordinates: { type: [Number] } 
    } 
}) 
//LocationSchema.index({ loc: "2dsphere", category: 1 },{ "background": false }); 
LocationSchema.index({ category: 1, loc: "2dsphere" }); 

var Location = mongoose.model("location", LocationSchema); 
var mongoDB = 'mongodb://localhost/test'; 
mongoose.Promise = global.Promise; 
mongoose.connect(mongoDB, { useMongoClient: true }); 


var testUser = Location({ 
    userName: "Tester", 
    category: 1, 
    loc: { coordinates: [12.44, 55.69] } 
}); 

testUser.save(function (err) { 
    if (err) { 
    return console.log("UPPPPs: " + err); 
    } 
    console.log("User Saved, Try to find him:"); 

    let query = Location.find({ 
    category: 1, 
    loc: 
    { 
     $near: 
     { 
     $geometry: 
     { 
      type: "Point", 
      coordinates: [12.50, 55.71] 
     }, 
     $maxDistance: 600000 
     } 
    } 
    }) 
    query.exec(function (err, docs) { 
    if (err) { 
     return console.log("Err: " + err); 
    } 
    console.log("Found: " + JSON.stringify(docs)) 
    }) 
}); 

Solange wir "category" alles enthalten ist in Ordnung:

User Saved, Try to find him:
Mongoose: locations.find({ loc: { '$near': { '$geometry': { type: 'Point', coordinates: [ 12.5, 55.71 ] }, '$maxDistance': 600000 } }, category: 1 }, { fields: {} })
Found: [{"_id":"59f8f87554900a4e555d4e22","userName":"Tester","category":1,"__v":0,"loc":{"coordinates":[12.44,55.69],"type":"Point"}},{"_id":"59f8fabf50fcf54fc3dd01f6","userName":"Tester","category":1,"__v":0,"loc":{"coordinates":[12.44,55.69],"type":"Point"}}]

Der alternative Fall ist, einfach „Präfix“ der Index mit der Lage. ersten Sicherzustellen vorherigen Indizes oder die Sammlung löschen:

LocationSchema.index({ loc: "2dsphere", category: 1 },{ "background": false }); 

so gut wie Sie wahrscheinlich in der Gewohnheit "background": true der Einstellung sein sollten, sonst anfangen zu laufen in ihren Rennbedingungen auf Unit-Tests, wo der Index nicht wurde erstellt beendet bevor der Unit-Test-Code versucht, ihn zu verwenden.

0

Meine erste Lösung für dieses Problem war die Erstellung des Index über die mLab-Webschnittstelle, die wie ein Zauber wirkte.

Ich habe die von Neil vorgeschlagene Lösung ausprobiert, aber das scheitert immer noch. Die detaillierten Anweisungen zu den Indizes, die Neil jedoch gegeben hat, haben mich auf die Lösung des Problems aufmerksam gemacht. Es war ein Timing-Problem (das Sie nicht immer sehen, wenn Sie die Datenbank lokal ausführen) in Bezug auf meine Test-Code hat Folgendes getan: Erstellt den Index, erstellt ein Location-Dokument (das erste Mal wird auch die Sammlung erstellen) und dann habe ich im callback von save versucht den user zu finden. Es scheint, dass der Index hier noch nicht erstellt wurde, was den Fehler verursacht hat.

Wenn ich die Find-Methode eine Sekunde verzögert, funktioniert es mit setTimeout gut.

Aber dennoch, dank Neil für wertvolle Informationen über den richtigen Weg Indizes verwenden (im Hintergrund) :-)

+0

Sorry, aber Sie sind einfach falsch. Wie bereits erwähnt, sollten Sie sich über das Timing bei der Indexerstellung im Klaren sein, aber wie ich anhand einer reproduzierbaren Auflistung gezeigt habe, ist es die ** Indexreihenfolge **, aus der Sie den Fehler erhalten. MongoDB kann den richtigen Index nicht auswählen, wenn das ** "Präfix" ** für diesen Index nicht in der Abfrage enthalten ist. Das sagt die Antwort, denn das war das Problem in Ihrem Code. Sie haben '' category '' nicht eingeschlossen, welches das Präfix des Indexes in Ihrer Anfrage ist. Wenn Sie einen Index verwenden, dem das Präfix "location" vorangestellt ist oder das andere Präfix tatsächlich enthält, wird das tatsächlich gelöst. –

Verwandte Themen