2017-10-31 7 views
1

내가이 오류를 얻을쿼리 2dsphere 인덱스 누락에 대해 불평하지만, 나는 다음과 같은 코드를 실행하면

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

이 (더 크게 예를 들어, 필수로 내려 삶은)입니다 :

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

을 그러나 인덱스는 아래에 있습니다 (10 줄 참조). 아래 mlab의 스크린 샷. 무엇이 잘못 되었습니까? : enter image description here

+0

:-) 인덱스 (배경)을 사용하는 올바른 방법에 대한 중요한 정보에 대한 닐 덕분에 당신이 당신의 문제를 해결하지 않는 생각 제공된 대답 뭔가가 있나요? 그렇다면 정확한 답변이 필요한 사항을 명확히하기 위해 답변에 의견을 말하십시오. 실제로 질문에 답하는 경우 질문에 [답변 수락] (https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work)을 적어주십시오. ask –

답변

1

일반적으로 색인을 사용하는 방법에 대한 규칙을 위반합니다. "2dsphere"인덱스가 복합 인덱스의 "첫 번째"속성 인 것은 no restriction이지만 실제로 "쿼리"가 인덱스가 선택되도록의 첫 번째 속성 인 을 실제로 처리하는 것이 매우 중요합니다 .

이 내용은 복합 색인에 대한 설명서의 Prefixes에서 다룹니다. 발췌에서 : 조회가 "loc"처음를 참조하고 "category"를 포함하지 않는

{ "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.

때문에, 인덱스가 선택하여 MongoDB는 오류를 반환되지 않습니다.

그래서 정의한 색인을 사용하려면 실제로 "category"을 쿼리해야합니다. 당신의 명부 개정 :만큼 우리가 "category" 모든 것을 포함로

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

것은 괜찮 :

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"}}]

대체의 경우는 단순히 "접두사"위치에 인덱스. 당신은 아마 "background": true을 설정하는 습관을해야 당신은 인덱스가 생성되고 완료되지 않았 단위 테스트에서 경쟁 조건으로 실행 시작, 다른뿐만 아니라

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

을 : 확실히 만드는 것은 이전 인덱스 또는 첫 번째 컬렉션을 떨어 뜨리지 유닛 테스트 코드가 그것을 사용하기 전에.

0

이 문제의 첫 번째 해결 방법은 매력처럼 작동하는 mLab 웹 인터페이스를 통해 색인을 만드는 것입니다.

나는 Neil이 제안한 해결책을 시도했지만 여전히 실패합니다. 그러나 Neil이 제시 한 인덱스와 관련된 자세한 지침은이 문제에 대한 해결책을 제시해주었습니다. 내 테스트 코드가 다음과 같은 작업과 관련하여 타이밍 문제 (데이터베이스를 로컬로 실행하는지 항상 확인할 수있는 것은 아닙니다) : 색인을 작성하고 위치 문서를 작성했으며 (처음으로 모음을 작성 함), 그런 다음 save에 의해 제공된 콜백에서 사용자를 찾으려고 시도했습니다. 오류가 발생한 색인이 아직 여기에 생성되지 않은 것으로 보입니다.

find 메소드를 잠깐 지연하면 setTimeout을 사용하면 정상적으로 작동합니다.

하지만 여전히,

+0

미안하지만 당신은 틀린 것일뿐입니다. 앞서 언급 했듯 실제로 인덱스 생성의 타이밍을 알고 있어야하지만 재현 가능한 목록으로 시연했듯이 ** 인덱스 주문 **에 오류가 표시됩니다. MongoDB는 해당 인덱스에 대한 ** "prefix"**가 쿼리에 포함되지 않은 경우 올바른 인덱스를 선택할 수 없습니다. 이것이 주어진 답변에서 말하는 것입니다. 왜냐하면 그것은 당신의 코드에서 문제 였기 때문입니다. 쿼리의 색인 접두사 인 "category"는 포함하지 않았습니다. ''location "'접두어가 붙은 인덱스를 사용하거나 실제로 다른 접두어를 포함하는 인덱스를 사용하는 것은 실제로 해결됩니다. –