2012-01-07 31 views
17

Tôi có hai bộ sưu tập MongoDB chia sẻ một _id chung. Sử dụng vỏ mongo, tôi muốn tìm tất cả các tài liệu trong một bộ sưu tập không có _id phù hợp trong bộ sưu tập khác.Lấy "dữ liệu từ bộ sưu tập b không có trong bộ sưu tập" trong truy vấn shell MongoDB

Ví dụ:

> db.Test.insert({ "_id" : ObjectId("4f08a75f306b428fb9d8bb2e"), "foo" : 1 }) 
> db.Test.insert({ "_id" : ObjectId("4f08a766306b428fb9d8bb2f"), "foo" : 2 }) 
> db.Test.insert({ "_id" : ObjectId("4f08a767306b428fb9d8bb30"), "foo" : 3 }) 
> db.Test.insert({ "_id" : ObjectId("4f08a769306b428fb9d8bb31"), "foo" : 4 }) 
> db.Test.find() 
{ "_id" : ObjectId("4f08a75f306b428fb9d8bb2e"), "foo" : 1 } 
{ "_id" : ObjectId("4f08a766306b428fb9d8bb2f"), "foo" : 2 } 
{ "_id" : ObjectId("4f08a767306b428fb9d8bb30"), "foo" : 3 } 
{ "_id" : ObjectId("4f08a769306b428fb9d8bb31"), "foo" : 4 } 
> db.Test2.insert({ "_id" : ObjectId("4f08a75f306b428fb9d8bb2e"), "bar" : 1 }); 
> db.Test2.insert({ "_id" : ObjectId("4f08a766306b428fb9d8bb2f"), "bar" : 2 }); 
> db.Test2.find() 
{ "_id" : ObjectId("4f08a75f306b428fb9d8bb2e"), "bar" : 1 } 
{ "_id" : ObjectId("4f08a766306b428fb9d8bb2f"), "bar" : 2 } 

Bây giờ tôi muốn có một số thắc mắc hoặc các truy vấn mà trả về hai tài liệu trong thử nghiệm nơi của _id không phù hợp với bất kỳ tài liệu trong Test2:

{ "_id" : ObjectId("4f08a767306b428fb9d8bb30"), "foo" : 3 } 
{ "_id" : ObjectId("4f08a769306b428fb9d8bb31"), "foo" : 4 } 

Tôi đã thử khác nhau các kết hợp $ not, $ ne, $ hoặc, $ in nhưng không thể có được kết hợp và cú pháp đúng. Ngoài ra, tôi không quan tâm nếu db.Test2.find({}, {"_id": 1}) được thực hiện trước tiên, được lưu vào một số biến, sau đó được sử dụng trong truy vấn thứ hai (mặc dù tôi không thể làm điều đó để hoạt động).

Cập nhật: Câu trả lời của Zachary trỏ tới $ nin đã trả lời phần quan trọng của câu hỏi. Ví dụ, công trình này:

> db.Test.find({"_id": {"$nin": [ObjectId("4f08a75f306b428fb9d8bb2e"), ObjectId("4f08a766306b428fb9d8bb2f")]}}) 
{ "_id" : ObjectId("4f08a767306b428fb9d8bb30"), "foo" : 3 } 
{ "_id" : ObjectId("4f08a769306b428fb9d8bb31"), "foo" : 4 } 

Nhưng (và thừa nhận đây không phải là khả năng mở rộng nhưng cố gắng để nó anyway vì nó không phải là một vấn đề trong tình huống này) tôi vẫn không thể kết hợp hai truy vấn với nhau trong vỏ. Đây là cảm giác mà tôi có thể nhận được, mà rõ ràng là ít hơn lý tưởng:

vals = db.Test2.find({}, {"_id": 1}).toArray() 
db.Test.find({"_id": {"$nin": [ObjectId(vals[0]._id), ObjectId(vals[1]._id)]}}) 

Có cách nào để trở lại chỉ các giá trị trong lệnh find để Vals có thể được sử dụng trực tiếp như các mảng đầu vào đến $ nin?

Trả lời

12

Bạn sẽ phải lưu các số từ bộ sưu tập A để không kéo chúng ra khỏi bộ sưu tập B, nhưng bạn có thể làm điều đó bằng cách sử dụng $nin. Xem Advanced Queries cho tất cả các toán tử MongoDB.

truy vấn cuối của bạn, bằng cách sử dụng ví dụ bạn đưa ra sẽ giống như thế:

db.Test.find({"_id": {"$nin": [ObjectId("4f08a75f306b428fb9d8bb2e"), ObjectId("4f08a766306b428fb9d8bb2f")]}})

Lưu ý rằng phương pháp này sẽ không quy mô. Nếu bạn cần một giải pháp có quy mô, bạn nên đặt cờ trong bộ sưu tập A và B cho biết liệu _id có nằm trong bộ sưu tập khác và sau đó truy vấn không.

cập nhật cho phần thứ hai:

Phần thứ hai là không thể. MongoDB không hỗ trợ các phép nối hoặc bất kỳ kiểu truy vấn chéo nào giữa các bộ sưu tập trong một truy vấn đơn lẻ. Truy vấn từ một bộ sưu tập, lưu kết quả và sau đó truy vấn từ thứ hai là lựa chọn duy nhất của bạn trừ khi bạn nhúng dữ liệu vào các hàng như tôi đã đề cập trước đó.

+1

Khiếu nại nhỏ: khái niệm là đúng, nhưng bạn đã nhận được Test và Test2 ngược trong câu trả lời. "Bây giờ tôi muốn một số truy vấn hoặc truy vấn trả về hai tài liệu trong Kiểm tra trong đó _id không khớp với bất kỳ tài liệu nào trong Test2" –

+0

'> db.Test.find ({" _ id ": {" $ nin ": [ObjectId (" 4f08a75f306b428fb9d8bb2e "), ObjectId (" 4f08a766306b428fb9d8bb2f ")]}});' cho '{ "_id": ObjectId (" 4f08a767306b428fb9d8bb30 "), "foo": 3} { "_id": ObjectId (" 4f08a769306b428fb9d8bb31") , "foo": 4} ' –

+0

Cảm ơn, đã trả lời phần quan trọng của câu hỏi, nhưng điều này không hữu ích lắm mà không trả lời phần thứ hai. Tôi đã cập nhật câu hỏi để phản ánh. – Raman

26

Trả lời câu hỏi tiếp theo của bạn. Tôi muốn sử dụng map().

Với này:

> b1 = {i: 1} 
> db.b.save(b1) 
> db.b.save({i: 2}) 
> db.a.save({_id: b1._id}) 

Tất cả bạn cần là:

> vals = db.a.find({}, {id: 1}).map(function(a){return a._id;}) 
> db.b.find({_id: {$nin: vals}}) 

trả về

{ "_id" : ObjectId("4f08c60d6b5e49fa3f6b46c1"), "i" : 2 } 
+0

Ahh, 'map', ngọt ngào! Điều đó hoạt động hoàn hảo. Ước gì tôi có thể chấp nhận cả câu trả lời của Zachary và của bạn. – Raman

+0

BTW, tất cả các phương thức con trỏ có thể được ghi lại ở đâu đó? Tôi không thấy chức năng 'map' được đề cập tại http://www.mongodb.org/display/DOCS/Queries+and+Cursors, cũng như tại http://www.mongodb.org/display/DOCS/Advanced+ Truy vấn # AdvancedQueries-CursorMethods. – Raman

+2

'map' chỉ là một hàm thư viện chuẩn javascript tốt, lỗi thời chạy trên mảng được kéo ra khỏi Mongo. Vỏ Mongo hỗ trợ JS tùy ý. –

0

Tôi đã thực hiện một kịch bản, đánh dấu tất cả các tài liệu về bộ sưu tập thứ hai xuất hiện trong bộ sưu tập đầu tiên. Sau đó, xử lý các tài liệu thu thập thứ hai.

var first = db.firstCollection.aggregate([ {'$unwind':'$secondCollectionField'} ]) 

while (first.hasNext()){ var doc = first.next(); db.secondCollection.update({_id:doc.secondCollectionField} ,{$set:{firstCollectionField:doc._id}}); } 

... quá trình bộ sưu tập thứ hai mà không có dấu

db.secondCollection.find({"firstCollectionField":{$exists:false}}) 
0

db.bar.find ({_ id: {$ nin: db.foo.find ({}, {_ id: 1}). toArray()}})

+0

Câu hỏi này đã được trả lời nhiều hơn trước đây. Vui lòng thêm thông tin thêm về câu trả lời của bạn hoặc xóa nó –

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