MongoDB의 $in 조항은 주문을 보증합니까?
MongoDB의 절을 사용할 때 반환되는 문서의 순서는 항상 array 인수의 순서에 대응합니까?
앞서 기술한 바와 같이 $in 절 배열의 인수 순서는 문서가 어떻게 검색되는지 순서를 반영하지 않습니다.물론 자연순서 또는 그림과 같이 선택한 지수순서가 됩니다.
이 순서를 유지할 필요가 있는 경우는, 기본적으로 2개의 옵션이 있습니다.
를 예 어 들 음 은 치 치 관 봅 so let다 of가시 were일해'가고 that on say정s matching같, you다한이 the values과다_id
in your documents with an array that is going to be passed in to the 에 전달되는 배열이 포함된 문서에서$in
as ~하듯이[ 4, 2, 8 ]
.
Aggregate를 사용한 접근법
var list = [ 4, 2, 8 ];
db.collection.aggregate([
// Match the selected documents by "_id"
{ "$match": {
"_id": { "$in": [ 4, 2, 8 ] },
},
// Project a "weight" to each document
{ "$project": {
"weight": { "$cond": [
{ "$eq": [ "$_id", 4 ] },
1,
{ "$cond": [
{ "$eq": [ "$_id", 2 ] },
2,
3
]}
]}
}},
// Sort the results
{ "$sort": { "weight": 1 } }
])
그래서 그것은 확장 형태일 것입니다.그래서 그것이 확장된 형태일 것이다.기본적으로 값은 기 서 본 어 적 은 열 찬 달 가 마 과 지 what basically is것 happens is here as values of that전 to로는되배 just값일$in
you also construct a "nested" 또한 "유도"를 구성합니다.$cond
값을 테스트하고 적절한 무게를 할당합니다.값을 테스트하고 적절한 가중치를 할당합니다."weight" 값은 배열 내 요소의 순서를 반영하므로 원하는 순서로 결과를 얻기 위해 정렬 단계에 해당 값을 전달할 수 있습니다.
물론 실제로 다음과 같이 코드로 파이프라인 문을 "빌드"할 수 있습니다.
var list = [ 4, 2, 8 ];
var stack = [];
for (var i = list.length - 1; i > 0; i--) {
var rec = {
"$cond": [
{ "$eq": [ "$_id", list[i-1] ] },
i
]
};
if ( stack.length == 0 ) {
rec["$cond"].push( i+1 );
} else {
var lval = stack.pop();
rec["$cond"].push( lval );
}
stack.push( rec );
}
var pipeline = [
{ "$match": { "_id": { "$in": list } }},
{ "$project": { "weight": stack[0] }},
{ "$sort": { "weight": 1 } }
];
db.collection.aggregate( pipeline );
mapReduce를 사용한 접근법
물론 이 모든 것이 당신의 감성에 큰 영향을 미친다고 생각되면 mapReduce를 사용하여 동일한 작업을 수행할 수 있습니다. mapReduce는 단순해 보이지만 실행 속도는 다소 느려질 수 있습니다.
var list = [ 4, 2, 8 ];
db.collection.mapReduce(
function () {
var order = inputs.indexOf(this._id);
emit( order, { doc: this } );
},
function() {},
{
"out": { "inline": 1 },
"query": { "_id": { "$in": list } },
"scope": { "inputs": list } ,
"finalize": function (key, value) {
return value.doc;
}
}
)
이는 기본적으로 출력된 "키" 값이 입력 어레이에서 발생하는 방법에 대한 "인덱스 순서"에 따라 달라집니다.
입니다.$in
이미 정해진 순서로 목록을 가지고 있는 조건입니다.
MongoDB 버전 > = 3.4에만 적용되는 Aggregation 쿼리를 사용하는 다른 방법:
그 공적은 이 멋진 블로그 게시물에 있다.
다음 순서로 가져올 문서 예제 -
var order = [ "David", "Charlie", "Tess" ];
쿼리 -
var query = [
{$match: {name: {$in: order}}},
{$addFields: {"__order": {$indexOfArray: [order, "$name" ]}}},
{$sort: {"__order": 1}}
];
var result = db.users.aggregate(query);
이러한 집약 오퍼레이터가 사용하는 것을 설명하는 투고로부터의 또 다른 인용:
"$addFields" 단계는 3.4의 새로운 단계로, 다른 모든 기존 필드를 몰라도 새 필드를 기존 문서에 "$projection"할 수 있습니다.새로운 "$indexOfArray" 식은 지정된 배열에서 특정 요소의 위치를 반환합니다.
으로는, 「 」입니다.addFields
「」를 합니다.order
되었을 때 문서에 필드 및 이 문서는 ""를 참조하십시오.order
필드는 제공된 어레이의 원래 순서를 나타냅니다.그런 다음 이 필드를 기준으로 문서를 정렬합니다.
「 를 합니다.aggregate
또은 , 을 사용하는 입니다.find
다음으로 다음 명령을 사용하여 문서 결과를 클라이언트 측으로 정렬합니다.
경우,$in
값은 다음과 같은 접근방식을 사용할 수 있는 숫자와 같은 원시 유형입니다.
var ids = [4, 2, 8, 1, 9, 3, 5, 6];
MyModel.find({ _id: { $in: ids } }).exec(function(err, docs) {
docs.sort(function(a, b) {
// Sort docs by the order of their _id values in ids.
return ids.indexOf(a._id) - ids.indexOf(b._id);
});
});
경우,$in
이란 '비동형이다'와 같이 비동형입니다'를 말합니다.ObjectId
또 합니다. s, 하다, 하다, 하다, 하다, 하다.indexOf
이 경우 참조에 의해 비교합니다.
Node.js 4.x+를 사용하는 경우 및 를 사용하여 이 문제를 해결할 수 있습니다.sort
★★★★
docs.sort((a, b) => ids.findIndex(id => a._id.equals(id)) -
ids.findIndex(id => b._id.equals(id)));
또는 Node.js 버전(언더스코어/로드시 포함):
docs.sort(function (a, b) {
return _.findIndex(ids, function (id) { return a._id.equals(id); }) -
_.findIndex(ids, function (id) { return b._id.equals(id); });
});
mongo가 배열을 반환한 후 결과를 쉽게 정렬할 수 있는 방법은 id를 키로 하는 개체를 만든 후 지정된 _id 위에 매핑하여 올바른 배열 순서를 반환하는 것입니다.
async function batchUsers(Users, keys) {
const unorderedUsers = await Users.find({_id: {$in: keys}}).toArray()
let obj = {}
unorderedUsers.forEach(x => obj[x._id]=x)
const ordered = keys.map(key => obj[key])
return ordered
}
Jonny와 비슷하다HK의 솔루션, 당신은 반품된 문서를 다시 주문할 수 있습니다.find
가 JavaScript에에서 "JavaScript"를 조합하여 사용합니다.map
및Array.prototype.find
EcmaScript 2015:
Collection.find({ _id: { $in: idArray } }).toArray(function(err, res) {
var orderedResults = idArray.map(function(id) {
return res.find(function(document) {
return document._id.equals(id);
});
});
});
주의사항:
- 위의 코드는 Mongoose가 아닌 Mongo 노드 드라이버를 사용하고 있습니다.
idArray
는 의 is is is is is의 입니다.ObjectId
- 만, 각 는, 「 에서 조작할 수 .
map
이치노
이 질문은 Mongoose JS 프레임워크와 관련된 것으로 알고 있습니다만, 중복된 것은 범용이므로 Python(PyMongo) 솔루션을 여기에 투고해 주셨으면 합니다.
things = list(db.things.find({'_id': {'$in': id_array}}))
things.sort(key=lambda thing: id_array.index(thing['_id']))
# things are now sorted according to id_array order
항상? 절대.순서는 항상 동일합니다.정의되지 않은 순서(아마 문서가 저장되는 실제 순서)입니다.당신이 분류하지 않는 한.
2021년 이후 MongoDb 3.6(테스트 완료)을 사용하여 주문을 유지하는 짧고 우아한 솔루션이 여기에 있습니다.
const idList = ['123', '124', '125']
const out = await db
.collection('YourCollection')
.aggregate([
// Change uuid to your `id` field
{ $match: { uuid: { $in: idList } } },
{
$project: {
uuid: 1,
date: 1,
someOtherFieldToPreserve: 1,
// Addding this new field called index
index: {
// If we want index to start from 1, add an dummy value to the beggining of the idList array
$indexOfArray: [[0, ...idList], '$uuid'],
// Otherwise if 0,1,2 is fine just use this line
// $indexOfArray: [idList, '$uuid'],
},
},
},
// And finally sort the output by our index
{ $sort: { index: 1 } },
])
오래된 스레드인 것은 알지만 배열의 ID 값만 반환하는 경우 이 구문을 선택해야 할 수 있습니다.mongo ObjectId 형식과 일치하는 indexOf 값을 얻을 수 없는 것 같습니다.
obj.map = function() {
for(var i = 0; i < inputs.length; i++){
if(this._id.equals(inputs[i])) {
var order = i;
}
}
emit(order, {doc: this});
};
'ObjectId()' 래퍼 없이 mongo ObjectId .toString을 변환하는 방법 - 값만?
$or 조항으로 주문을 보증할 수 있습니다.
사용방법$or: [ _ids.map(_id => ({_id}))]
대신.
이것은 Mongo에서 결과를 가져온 후의 코드 솔루션입니다.맵을 사용하여 인덱스를 저장한 다음 값을 바꿉니다.
catDetails := make([]CategoryDetail, 0)
err = sess.DB(mdb).C("category").
Find(bson.M{
"_id": bson.M{"$in": path},
"is_active": 1,
"name": bson.M{"$ne": ""},
"url.path": bson.M{"$exists": true, "$ne": ""},
}).
Select(
bson.M{
"is_active": 1,
"name": 1,
"url.path": 1,
}).All(&catDetails)
if err != nil{
return
}
categoryOrderMap := make(map[int]int)
for index, v := range catDetails {
categoryOrderMap[v.Id] = index
}
counter := 0
for i := 0; counter < len(categoryOrderMap); i++ {
if catId := int(path[i].(float64)); catId > 0 {
fmt.Println("cat", catId)
if swapIndex, exists := categoryOrderMap[catId]; exists {
if counter != swapIndex {
catDetails[swapIndex], catDetails[counter] = catDetails[counter], catDetails[swapIndex]
categoryOrderMap[catId] = counter
categoryOrderMap[catDetails[swapIndex].Id] = swapIndex
}
counter++
}
}
}
언급URL : https://stackoverflow.com/questions/22797768/does-mongodbs-in-clause-guarantee-order
'programing' 카테고리의 다른 글
jQuery.ajax를 사용하여 멀티파트/폼데이터 전송 (0) | 2023.03.22 |
---|---|
Woocommerce에서 제품 이름별로 제품 퍼멀링크 가져오기 (0) | 2023.03.17 |
AngularJs .$setPris틴에서 폼 리셋 (0) | 2023.03.17 |
유형 스크립트 맵에 대한 반복 (0) | 2023.03.17 |
각의 모달 닫히지 않게 하려면 어떻게 해야 하나요? (0) | 2023.03.17 |