2017-01-09 2 views
4

MongoDB를 사용하여 시계열을 처리하려고합니다. 공동체가 채택한 일반적인 해결책은 하위 문서를 사용하여 서로 다른 수준의 정보를 저장하는 것입니다 ( Schema Design for Time Series Data in MongoDB 참조).MongoDB Collection update : 기본값으로 문서 초기화

{ 
    timestamp_minute: ISODate("2013-10-10T23:06:00.000Z"), 
    type: “memory_used”, 
    values: [ 
    999999, // 1 second 
    … 
    1000000, // nth second 
    1500000, // n+1th second 
    … 
    2000000 // 60th 
    ] 
} 

서 예약 정보에 의해 색인되고, 각각의 제 더 상세한 정보를 저장하는 하위 문서를 포함

는 예를 들어, 다음의 문서를보십시오.

지금까지 그렇게 좋았습니다. 이런 종류의 접근법이 제대로 작동하도록 최적화가 필요합니다

Another optimization [..] is preallocating all documents for the upcoming time period; This never causes an existing document to grow or be moved on disk.

이 하나가 update 방법에 $setOnInsert 속성을 사용할 수 있습니다 위의 최적화를 구현하려면.

db.getCollection('aCollection').update(
    { 
     timestamp_minute: ISODate("2013-10-10T23:06:00.000Z"), 
     type: “memory_used” 
    }, 
    { 
     $setOnInsert: { values: {'0': 0, '1': 0, '2': 0}}, 
     $inc: {"values.30": 1} 
    }, 
    { upsert: true } 
) 

동일한 업데이트를 두 가지 다른 작업에서 같은 필드를 사용할 수 없다는 문제가 있습니다. 이 문제는이 issue에 추적

Cannot update 'values' and 'values.30' at the same time 

: 위의 업데이트 istruction는 다음과 같은 오류가 발생합니다.

내 질문은 : 어떤 해결책이 있습니까?은 내가 인덱스 필드 사전 (위의 예에서, 필드의 값 type.

감사의 값을 알 수 없기 때문에 나는 빈 문서를 미리 할당 어떤 배치를 사용할 수 없습니다 접두사 미리.

답변

4

나와 내 동료들은 해결 방법을 발견했다. 우리는

. 세 단계로 초기화를 호출하여 MongoDB가 하나의 문서에 대한 작업의 원 자성을 보장 것을 기억 할 수 있습니다.이 사실로 우리가 작동 할 수 염두에 다음과 같은 방법으로 :

  1. 지정된 시간 청크에서 카운터를 올바르게 증가시키면서 문서를 업데이트하십시오. 어떤 업 그레 이드도하지 말고 그냥 옛날 방식의 업데이트 작업입니다. update 문의 실행은 작성된 문서의 수를 반환한다는 것을 기억하십시오. 작성된 문서 수가 0보다 크면 작업이 완료된 것입니다.
  2. 업데이트로 작성된 문서 수가 0이면 업데이트 할 상대 문서가 아직 컬렉션에 없음을 의미합니다. 지정된 태그에 대해 전체 문서를 삽입하십시오. 모든 카운터 (필드 값)를 0으로 설정하십시오. 또한 insert 문을 실행하면 작성된 문서 수가 반환됩니다. 0을 반환하거나 예외가 발생하면 다른 프로세스가 이미 동일한 태그에 문서를 삽입했음을 의미하지 않습니다.
  3. 위의 업데이트를 다시 실행하십시오.

코드는 다음 코드 스 니펫과 유사해야합니다._id 값이 문서에서 다른 필드로부터 유도되어야한다 전제 보유 경우

// Firt of all, try the update 
var result = db.test.update(
    {timestamp_minute: ISODate("2013-10-10T23:06:00.000Z"), type: “memory_used”}, 
    {$inc: {"values.39": 1}}, 
    {upsert: false} 
); 
// If the update do not succeed, then try to insert the document 
if (result.nModified === 0) { 
    try { 
    db.test.insert(/* Put here the whole document */); 
    } catch (err) { 
    console.log(err); 
    } 
    // Here we are sure that the document exists. 
    // Retry to execute the update statement 
    db.test.update(/* Same update as above */); 
} 

상기 과정은 작동한다. 이 예에서 _id 값은 '2013-10-10T23:06:00.000Z-memory_used입니다. 이 기술 만 사용하면 지점 2의 삽입이 제대로 실패합니다.

+1

삽입이 실패하는 이유는 무엇입니까? 유형 및 타임 스탬프에 대한 고유 색인이 있습니까? –

+0

맞아,이 지점을 삽입하는 데 그리워. '_id'는 문서의 다른 필드에서 파생되어야합니다 (예 :'-' char로 결합). –