2012-01-30 2 views
2

MongoDB를 사용하여 문서 모음을 보관하고 있습니다.MongoDB - 문서의 마지막 버전을 가져 오는 가장 효율적인 방법입니다.

각 문서에는 ObjectId 인 _id (버전)이 있습니다. 각 문서에는 서로 다른 버전에서 공유되는 documentId가 있습니다. 이것 역시 첫 번째 문서가 생성 될 때 할당 된 객체입니다.

documentId가 있으면 문서의 최신 버전을 찾는 가장 효율적인 방법은 무엇입니까?

e.e. _id = max (_id) 및 documentId = x 인 레코드를 가져오고 싶습니다.

MapReduce를 사용해야합니까? 사전에

감사합니다,

답변

6

이 두 필드 (documentId, _id)를 포함하는 인덱스를 추가하고 (무엇에) 최대 사용하지 않는? documentId = x로 쿼리를 사용하고 DESC를 _id로 제한하고 limit (1) 결과를 최신으로 가져옵니다. 인덱스의 적절한 정렬 순서에 대한 기억 (DESC도)

뭐 그런

db.collection.find({documentId : "x"}).sort({_id : -1}).limit(1) 

다른 접근 방식 (더 비정규)는 같은 문서를 다른 소식 모음을 사용하는 것입니다 :의

{ 
    documentId : "x", 
    latestVersionId : ... 
} 

사용 원자 적 연산은이 컬렉션을 안전하게 업데이트 할 수 있습니다. 적절한 인덱스를 추가하면 쿼리가 번개처럼 빠르게 수행됩니다.

고려해야 할 한 가지가 있습니다. ObjectID를 항상 최신 버전으로 안전하게 사용할 수 있는지 여부는 확실하지 않습니다. 타임 스탬프를 사용하는 것이 더 확실한 접근법 일 수 있습니다.

+0

완벽, 고마워요 다이몬. 두 번째 옵션과 관련하여 질문이 있지만 새 레코드가 주 문서 컬렉션에 삽입되는 경우 비정규 "인덱스"컬렉션을 원자 적으로 삽입하고 업데이트하는 방법은 무엇입니까? 첫 번째 문서의 인덱스 레코드가 업데이트되기 전에 다른 문서 인스턴스를 삽입 할 수 있습니까? 말이 돼? 문서가 변경되지 않았는지 확인하려면 findAndModify 권한을 사용할 수 있습니까? 나는 그것이 최신 _id를 얻었고 다시 시도 할 것인가? 그것이 요점입니까? 다시 한번 감사드립니다. – sambomartin

+0

MongoDB는 RDBMS와 같은 트리거를 지원하지 않으므로 애플리케이션 측에서 지원합니다. findAndModify를 사용하여 id/timestamp가 더 낮은 문서를 찾은 다음 문서를 업데이트하고 업데이트 할 수 있습니다. findAndModify는 원자 적 연산이기 때문에 새 값이 현재보다 더 작은 경우에만 문서를 업데이트합니다. 이렇게하면 동시 업데이트에 대해 걱정할 필요가 없습니다. – Daimon

+0

다시 한번 감사드립니다. 버전 번호 나 타임 스탬프를 사용한다고 가정하면 다른 프로세스가 다른 문서 인스턴스를 추가하고 "색인"문서를 업데이트하면 findAndModfy가 실패합니다. findAndModify는 현재 버전보다 버전이 더 최신인 "index"doc을 업데이트하고 업데이트합니다. 이 문제가 발생하면 단순히 최신 버전을 가져 와서 색인 문서를 다시 업데이트해야합니까? 죄송합니다. 아무 것도 반복하지 않은 경우 내 마음에 분명히 표시하고 싶습니다. – sambomartin

1

나는 sortlimit을 사용하여 Daimon의 첫 번째 대답과 동일하게 입력했습니다. _id가 생성되는 방식 때문에 일부 드라이버 (최하위 부분에 대해 증가 대신 임의의 숫자를 사용하는)에서 특히 권장하지 않습니다. 가장 중요한 부분으로 2 분의 1 (밀리 세컨드와 같이 작은 것의 반대) 해상도를 갖지만 마지막 숫자는 임의의 숫자가 될 수 있습니다. 따라서 사용자가 두 번째로 두 번 저장하면 (아마도 가능성은 없지만 주목할만한 가치가 있음) 약간의 최신 문서가 종료 될 수 있습니다.

ObjectID의 구조에 대한 자세한 내용은 http://www.mongodb.org/display/DOCS/Object+IDs#ObjectIDs-BSONObjectIDSpecification을 참조하십시오.

나는 당신의 문서에 명시의 versionNumber 필드를 추가하는 것이 좋습니다 것입니다, 그래서 당신과 같이 해당 필드를 사용하여 비슷한 방식으로 조회 할 수 있습니다

db.coll.find({documentId: <id>}).sort({versionNum: -1}).limit(1); 

편집 주석 질문에 대답

일반 DateTime을 MongoDB에 직접 저장할 수는 있지만 밀리 초 정밀도 만 MongoDB의 "DateTime"형식으로 저장합니다. 그게 충분하다면, 더 간단하게 할 수 있습니다.

BsonDocument doc = new BsonDocument("dt", DateTime.UtcNow); 
coll.Insert (doc); 
doc = coll.FindOne(); 
// see it doesn't have precision... 
Console.WriteLine(doc.GetValue("dt").AsUniversalTime.Ticks); 

원한다면.NET 날짜 시간 (틱)/타임 스탬프의 정밀도는, 당신은 같은 일을 얻을 캐스트의 무리를 수행 할 수 있습니다

BsonDocument doc = new BsonDocument("dt", new BsonTimestamp(DateTime.UtcNow.Ticks)); 
coll.Insert (doc); 
doc = coll.FindOne(); 
// see it does have precision 
Console.WriteLine(new DateTime(doc.GetValue("dt").AsBsonTimestamp.Value).Ticks); 

업데이 트를 다시!

BsonTimestamp의 실제 용도는 두 번째 해상도 내에서 고유 한 타임 스탬프를 생성하는 것입니다. 따라서, 코드의 마지막 몇 줄에있는 것처럼 실제로 코드를 남용하지 않아도됩니다. 실제로 결과의 순서가 엉망이 될 것입니다. TickTime (100 나노초) 해상도로 DateTime을 저장해야하는 경우 mongodb에서 정렬 할 수있는 64 비트 int "틱"을 저장 한 다음 꺼낸 후 DateTime으로 래핑해야합니다 다시 데이터베이스, 이렇게 :

BsonDocument doc = new BsonDocument("dt", DateTime.UtcNow.Ticks); 
coll.Insert (doc); 
doc = coll.FindOne(); 
DateTime dt = new DateTime(doc.GetValue("dt").AsInt64); 
// see it does have precision 
Console.WriteLine(dt.Ticks); 
+0

감사합니다. – sambomartin

+0

정수 카운터 사용은 가능하지만 전혀 확장 할 수 없습니다 ... 고해상도 타임 스탬프를 사용하는 것이 더 나은 접근 방법입니다. 두 개의 문서가 동일한 타임 스탬프를 공유 할 가능성은 항상 있습니다.하지만 RDBMS를 사용하는 경우 업무상 중요한 경우 더 나은 접근법인가? – Daimon

+0

확인. 말이된다. 그것은 선교 적으로 중요하지 않지만 분명히 일해야합니다. RDBMS 개념을 뒤 흔드는 데 어려움. 입력 해 주셔서 감사합니다. (모두) – sambomartin

관련 문제