2010-06-29 31 views
40

Tài liệu MongoDB trên $in toán tử điều kiện không nói bất cứ điều gì về thứ tự. Nếu tôi chạy truy vấn của biểu mẫu

db.things.find({'_id': {'$in': id_array}}); 

thứ tự của kết quả trả về là gì? Và có cách nào để tôi nói với MongoDB "Tôi muốn các kết quả được sắp xếp sao cho chúng có cùng thứ tự như các id trong id_array?"

+1

Bất kỳ giải pháp nào cho 2.6? – Sekai

+0

giải pháp Python/PyMongo đơn giản: http://stackoverflow.com/a/40048951/304209 –

+0

Kiểm tra [this] (http://stackoverflow.com/a/42293303/4440874) answer. –

Trả lời

4

thứ tự của các kết quả không được đề cập bởi vì chúng sẽ không được đặt hàng theo bất kỳ cách nào đáng tin cậy. cách duy nhất để có được chúng ra lệnh sẽ được làm các truy vấn riêng biệt client-side cho từng hạng mục trong $ trong mảng

+0

OK, đó là những gì tôi mong đợi. Vì vậy, hãy nói rằng tôi đang thực hiện truy vấn thông qua PyMongo. Sau đó, tôi có thể: 1. Tạo một MongoDB riêng biệt cho mỗi id trong id_array và nối nó vào cuối danh sách (không hiệu quả do các truy vấn thừa) hoặc 2. Thực hiện truy vấn MongoDB đơn trong câu hỏi của tôi, sau đó sử dụng Python để sao chép các kết quả từ MongoDB vào một danh sách được sắp xếp đúng (không hiệu quả vì tôi đang sao chép một lượng lớn dữ liệu có khả năng ở phía máy khách)? Không có cách nào tốt hơn? Một số loại truy vấn tùy chỉnh mà tôi có thể chạy trên MongoDB sẽ sắp xếp kết quả trước khi chúng được trả về? –

+0

bạn có thể thay đổi giản đồ của mình. có một câu hỏi đang diễn ra trên danh sách người dùng mongodb ngay bây giờ thảo luận chính xác tùy chọn đó, cho chính xác câu hỏi này. nên có lẽ chỉ cần kiểm tra xem và theo dõi ở đó. – mdirolf

+3

Tôi có thể hơi muộn với bữa tiệc này, nhưng tôi đã gặp vấn đề này. Giải pháp của tôi là xây dựng một từ điển (trong trường hợp của tôi) 'ObjectId' đến vị trí (nghĩa là, vị trí trong danh sách tôi đã sử dụng cho truy vấn' $ in'), và sau đó sử dụng nó để sắp xếp lại đầu ra. Tôi đang hoạt động trên một số lượng nhỏ các mặt hàng, tuy nhiên, có lẽ điều này không hữu ích cho trường hợp của bạn. – dcrosta

11

được hỏi cho tính năng này trên JIRA:

nhanh chóng nhận được phản ứng khá tốt: sử dụng $or thay vì $in

c.find({ _id:{ $in:[ 1, 2, 0 ] } }).toArray() 

vs

c.find({ $or:[ { _id:1 }, { _id:2 }, { _id:0 } ] }).toArray() 

đọc các báo cáo lỗi để biết thêm.

Cập nhật:

Các $ hoặc công việc xung quanh Hack không còn công trình bắt đầu với 2.6.x - đó là một tác dụng phụ của thực hiện trong đó có changed.

+0

Không phải là khá dễ dàng/tốt đẹp khi bạn đang sản xuất danh sách lập trình, nhưng tốt mà có một giải pháp. – UpTheCreek

+7

Phương pháp này dường như không hoạt động từ 2.6.x, như đã đề cập trong nhận xét JIRA – rlay3

6

Tôi đã gặp vấn đề tương tự và giải pháp của tôi là tạo bản đồ băm để thực hiện ánh xạ giữa mảng id của tôi (truy vấn của tôi) và mảng kết quả của tôi từ MongoDB.

Công việc phụ là duyệt qua các mảng kết quả và chèn, cho mỗi mục, cặp khóa-giá trị mới: khóa là ID và giá trị là đối tượng kết quả.

Sau đó, khi tôi muốn duyệt kết quả theo thứ tự như truy vấn của tôi, tôi có thể sử dụng hashmap để truy lục đối tượng chính xác. Không phân loại, và không có tùy chọn Mongo DB ưa thích.

Trong javascript nó sẽ là một cái gì đó như:

//The order you want 
var queryIds = [ 8, 5, 3, 7 ]; 

//The results from MongoDB in an undefined order 
var resultsFromMongoDB = [ 
    {_id: 7, data: "d" }, 
    {_id: 8, data: "a" }, 
    {_id: 5, data: "b" }, 
    {_id: 3, data: "c" }, 
]; 

//The function to create a hashmap to do the mapping 
function createHashOfResults(results){ 
    var hash = {}; 

    for(var i = 0 ; i < results.length ; i++){ 
     var item = results[i]; 
     var id = item._id; 
     hash[ id ] = item; 
    } 

    return hash; 
} 

//Let's build the hashmap 
var hash = createHashOfResults(resultsFromMongoDB); 

//Now we can display the results in the order we want 
for(var i = 0 ; i < queryIds.length ; i++){ 
    var queryId = queryIds[i]; 
    var result = hash[queryId]; 
    console.log(result.data); 
} 

sẽ hiển thị này:

a 
b 
c 
d 
+0

Tôi cũng làm như vậy :) –

+0

Bạn không thể làm điều này trong bộ nhớ nếu dữ liệu rất lớn. –

4

câu trả lời @ Jason 's là điều đúng.

Giới thiệu về các câu trả lời khác: Tôi sẽ không khuyên bạn nên truy vấn từng câu hỏi bởi vì nó có thể mang lại các vấn đề về hiệu suất nghiêm trọng.

Ngoài câu trả lời @ Jason 's, nó có thể được tối ưu hóa sử dụng Array.reduce và Array.map phương pháp, như thế này:

//The order you want 
var queryIds = [8, 5, 3, 7]; 

//The results from MongoDB in an undefined order 
var resultsFromMongoDB = [ 
    {_id: 7, data: "d"}, 
    {_id: 8, data: "a"}, 
    {_id: 5, data: "b"}, 
    {_id: 3, data: "c"} 
]; 

var reorderedResults = naturalOrderResults(resultsFromMongoDB, queryIds); 


function naturalOrderResults(resultsFromMongoDB, queryIds) { 
    //Let's build the hashmap 
    var hashOfResults = resultsFromMongoDB.reduce(function (prev, curr) { 
     prev[curr._id] = curr; 
     return prev; 
    }, {}); 

    return queryIds.map(function(id) { return hashOfResults[id] }); 
} 
+0

Cải thiện tốt đẹp! Cảm ơn. – Jason

1

Nếu bạn không nhớ sử dụng dấu gạch dưới.js và không quá lo lắng về quy mô (IE, bạn không quan tâm đến số fetch -ing thay vì làm việc với con trỏ), đây là cách tôi duy trì trật tự:

var results = db.things.find({'_id': {'$in': id_array}}).fetch(); 
return _.sortBy(results, function(thing) { 
    return id_array.indexOf(thing._id); 
}); 
+0

tôi thấy một sự cân bằng ở đây: Cách tiếp cận này trông sạch hơn nhưng nó có thể sử dụng nhiều CPU hơn. Điều này xảy ra vì array.indexOf sẽ quét id_array cho mỗi mục trong mảng kết quả của bạn và sau khi tất cả công việc này kết thúc việc sử dụng tất cả các kết quả. Tự kiểm tra: https://jsfiddle.net/davidrc/gyjrtovu/ Tất nhiên đây không phải là vấn đề với giao diện người dùng (chúng tôi đang nói về một số ms), nhưng có thể đặt thêm tải khi chúng tôi chạy mã này trong phần phụ trợ với hàng tấn người dùng. –

+0

Đồng ý. Tôi phải làm điều này cho <50 mục để rõ ràng với ý định và ngắn gọn là ưu tiên hàng đầu của tôi. – Alexey

Các vấn đề liên quan