あなたが実際に代わり$and
の$or
条件を求めているように見えます。
$near
クエリが_id
値に与えられた$in
条件に合致
- 「と同様に」文書を結果:それはあなたが実際に望んでいた場合は、「両方」からの結果は考慮理にかなって。
$and
条件として
クエリは次のように書くことができます。
clublist.find({
"loc": { "$near": coords, "$maxDistance": maxDistance },
"_id": { "$in": branchId } // branchId is the array [108,109,110]
},function(err,branchData) {
/* Data needs to be "both" near as well has having the supplied
_id values. So at maximum only "three" results, provided all
"three" are within the maxDistance
*/
})
は、だからと、それはあなたが$or
を意味するが、その後、別の問題がある可能性が高いようだと考えます。
$or
は、地理空間インデックスが必要な$near
のようなクエリ操作では使用できません。したがって、このような操作はエラーになります:
clublist.find({
"$or": [
{ "loc": { "$near": coords, "$maxDistance": maxDistance } },
{ "_id": { "$in": branchId } } // branchId is the array [108,109,110]
]
},function(err,branchData) {
// err: "geoNear must be top-level expr"
})
これを実行するには、実際には別々のクエリを実行してから結果を結合します。これらは実際には別々の結果であるため、組み合わせに「並べ替える」ために「距離」を含めることをお勧めします。
良いツールはasync.parallel
です。さまざまな操作の結果を取得して1つのコールバックで処理できるため、これは良いツールです。 1はcontrainsあなたが別々に各クエリを実行している。この場合、
async.parallel(
[
function(callback) {
clublist.aggregate(
[
{ "$geoNear": {
"near": coords,
"distanceField": "distance",
"maxDistance": maxDistance
}},
{ "$limit": 50 }
],
callback
)
},
function(callback) {
clublist.aggregate(
[
{ "$geoNear": {
"near": coords,
"distanceField": "distance",
"query": { "_id": { "$in": branchId } }
}}
],
callback
)
}
],
function(err,results) {
if (err) throw err;
var branchData = [];
branchData = results.forEach(function(el) {
branchData = branchData.concat(el);
});
// Sort and return the 50 nearest
branchData = branchData.sort(function(a,b) {
return a.distance > b.distance
}).slice(0,50)
}
)
、:全体的な結果をソートするのに重要な部分である、実際に「プロジェクト」の結果への「距離」、集約$geoNear
もあります結果は"maxDistance"
であり、もう1つは$in
の引数に反しています。 「結合された」結果はセットの「限界」よりも大きいので、その結果を距離でソートし、組み合わせから合計の限界を返すだけで済みます。
これは、_id
の選択を考慮したい場合の方法ですが、実際には$near
に含まれていない「距離」が実際に返される可能性があります。しかし、あなたの意図は、結果の「上に」_id
選択をしているために常にだった場合
、あなたはその後、普通のクエリを使用することができますし、それらの結果について0
の距離を「注入」:
async.parallel(
[
function(callback) {
clublist.aggregate(
[
{ "$geoNear": {
"near": coords,
"distanceField": "distance",
"maxDistance": maxDistance
}},
{ "$limit": 50 }
],
callback
)
},
function(callback) {
clublist.find({ "_id": { "$in": branchId }}).toArray(function(err,branchData) {
branchData = branchData.map(function(doc) {
doc.distance = 0;
});
callback(err,branchData);
})
}
],
function(err,results) {
if (err) throw err;
var branchData = [];
branchData = results.forEach(function(el) {
branchData = branchData.concat(el);
});
// Sort and return the 50 nearest
branchData = branchData.sort(function(a,b) {
return a.distance > b.distance
}).slice(0,50)
}
)
同じソートでは、これらの値が上に保持され、他のクエリ操作の結果が返されます。
もちろん、指定された_id
の値が「両方の」クエリで返される「チャンス」があります。実際に.slice()
操作を実行する前に、または一般的に最終結果を返す前に、それが当てはまる場合や、可能であれば、配列の内容を "重複する" _id
値と単純に一致させることができます。これは、一意のキーを持つオブジェクトを使用し、次に配列に戻る単純なプロセスです。以下のような
何か:
function(err,results) {
if (err) throw err;
var branchData = [];
branchData = results.forEach(function(el) {
branchData = branchData.concat(el);
});
var uniqueBranch = {};
// Just keep unique _id for smallest distance value
for (var idx in branchData) {
if ((uniqueBranch.hasOwnProperty(branchData[idx]._id))
&& (branchData[idxx].distance > uniqueBranch[branchData[idx]._id].distance))
continue;
uniqueBranch[branchData[idx]._id] = branchData[idx];
}
// Go back to array, sort and slice
branchData = Object.keys(uniqueBranch).map(function(k) {
return uniqueBranch[k];
}).sort(function(a,b) {
return a.distance > b.distance;
}).slice(0,50);
}
私は質問が表示されません。 –
@AaronGillionはい。実際に問題を提示していない別の失敗。しかし、 "慎重に"見れば、 '{" _id ":{" $ in ":branchId}}'行が見えます。ここでの問題は、OPが実際に '$ or'クエリを望んでいるということです。なぜなら、' $と '条件としてプライマリキーに値のリストを与えるのは意味がないからです。だから彼らは "同様に"実際には$またはを意味していないことがあります。 "問題"は、このようなジオスペースインデックスで '$ or'を使うことはできませんし、他の" _id "が照会されたポイントに必ずしも近くないと考えることも意味がありません –