2012-01-07 1 views
17

공통 _id를 공유하는 두 개의 MongoDB 컬렉션이 있습니다. 몽고 셸을 사용하여 다른 컬렉션에 일치하는 _id가없는 모든 문서를 한 컬렉션에서 찾고 싶습니다.MongoDB 셸 쿼리에서 "컬렉션 b가 아닌 컬렉션 b의 데이터"가져 오기

예 : 나는 다양한 시도했습니다

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

:

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

지금 나는 _id 년대 Test2를에있는 모든 문서를 일치하지 않는 시험에 두 개의 문서를 반환 일부 쿼리 또는 쿼리를 원하는 $ not, $ ne, $ or, $ in의 조합은 올바른 조합과 구문을 얻을 수 없습니다. 또한, db.Test2.find({}, {"_id": 1})이 먼저 실행되고 두 번째 쿼리에서 사용되는 변수에 저장 되어도 상관 없습니다 (그래도 작동하지는 않지만).

업데이트 : $ n을 가리키는 Zachary의 대답이 질문의 핵심 부분에 응답했습니다.

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

하지만를 (이 인정하는 확장 성이 있지만,이 상황에서의 아닌 문제가 있기 때문에 어쨌든하려고하지 않습니다) 난 아직도 쉘 함께 두 개의 쿼리를 결합 할 수 없습니다 : 예를 들어,이 작동합니다. 이것은 분명히 이상적인보다 작은, 내가 얻을 수있는 가장 가까운 : 발스는 $ 닌에 배열 입력으로 직접 사용할 수 있도록 find 명령에 바로 값을 반환 할 수있는 방법이

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

있습니까?

답변

12

컬렉션 B에서 컬렉션을 다시 가져 오지 않으려면 컬렉션 A에서 _ids를 저장해야하지만 $nin을 사용하면됩니다. 모든 MongoDB 연산자에 대해서는 Advanced Queries을 참조하십시오. 이 방법은 확장되지 않습니다

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

참고 : 같이 보일 것이다 준 예제를 사용

최종 쿼리. 확장 가능한 솔루션이 필요한 경우 컬렉션 A와 B에서 _id가 다른 컬렉션에 있는지 플래그를 설정하고 대신 컬렉션에서 쿼리해야합니다.

는 두 번째 부분에 대한 업데이트 :

두 번째 부분은 불가능하다. MongoDB는 조인 또는 단일 쿼리에서 컬렉션 사이의 일종의 교차 쿼리를 지원하지 않습니다. 한 컬렉션에서 쿼리하고 결과를 저장 한 다음 두 번째 쿼리에서 쿼리하면 이전에 언급 한 것처럼 행 자체에 데이터를 포함하지 않는 한 유일한 선택입니다.

+1

사소한 불만 사항 : 개념은 맞지만 답변에서 Test와 Test2를 거꾸로 가져 왔습니다. "이제는 _id가 Test2의 어떤 문서와도 일치하지 않는 Test의 두 문서를 반환하는 쿼리 또는 쿼리를 원합니다." –

+0

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

+0

감사합니다. 질문의 핵심 부분에 답변했지만, 두 번째 부분에도 응답하지 않으면 매우 유용하지 않습니다. 나는 그 질문을 반영하도록 수정했다. – Raman

26

후속 조치에 대한 답변. 나는 map()을 사용할 것이다.

을 감안할 때이 :

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

당신이 필요로하는 모든이 : 두 번째 컬렉션 모든 문서를 표시, 내가 스크립트를했습니다

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

아,'map', 달콤한! 그건 완벽하게 작동합니다. 재커리의 대답과 당신의 대답을 모두 받아 들일 수 있기를 바랍니다. – Raman

+0

BTW, 어딘가에 문서화 된 가능한 모든 커서 방법입니까? 나는 http://www.mongodb.org/display/DOCS/Queries+and+Cursors 나 http://www.mongodb.org/display/DOCS/Advanced+에 언급 된'map' 함수를 보지 못했습니다. # AdvancedQueries-CursorMethods를 쿼리합니다. – Raman

+2

'map'은 Mongo에서 추출한 어레이에서 실행되는 오래된 자바 스크립트 표준 라이브러리 함수입니다. Mongo 쉘은 임의의 JS를 지원합니다. –

0

을 반환

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

그 첫 번째 컬렉션에 표시됩니다. 그런 다음 두 번째 수집 문서를 처리했습니다. 몽고 다음 코드 보인다 3.2에는 마크

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

가없는 제 컬렉션이 https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/#use-lookup-with-an-array 예에 기초

db.collectionb.aggregate([ 
    { 
     $lookup: 
     { 
      from: "collectiona", 
      localField: "collectionb_fk", 
      foreignField: "collectiona_fk", 
      as: "matched_docs" 
     } 
    }, 
    { 
     $match: { "matched_docs": { $eq: [] } } 
    } 
]); 

일할

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

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

... 프로세스

0

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

+0

이 질문은 전에 답변되었습니다. 답변에 대한 추가 정보를 추가하거나 삭제하십시오. –