source

mongodb: 없는 경우 삽입

ittop 2023. 2. 26. 10:30
반응형

mongodb: 없는 경우 삽입

매일 문서 재고(업데이트)를 받습니다.제가 원하는 것은 존재하지 않는 아이템을 하나씩 삽입하는 것입니다.

  • 또한 처음 삽입한 시간과 마지막으로 업데이트로 본 시간을 추적하고 싶습니다.
  • 나는 중복된 서류를 갖고 싶지 않다.
  • 이전에 저장되었지만 업데이트에 없는 문서를 제거하지 않습니다.
  • 기록의 95%(최소)는 매일 수정되지 않습니다.

Python 드라이버(pymongo)를 사용하고 있습니다.

현재 하고 있는 일은 (의사 코드)입니다.

for each document in update:
      existing_document = collection.find_one(document)
      if not existing_document:
           document['insertion_date'] = now
      else:
           document = existing_document
      document['last_update_date'] = now
      my_collection.save(document)

문제는 매우 느리다는 것입니다(10만개 미만의 레코드에 40분, 업데이트에 수백만 개 있습니다).이 작업을 하기 위한 기본 제공이 있는 것은 확실합니다만, update()의 문서는 mmmhhhhh...조금 간결합니다.(http://www.mongodb.org/display/DOCS/Updating )

어떻게 하면 더 빨리 할 수 있는지 조언해 주실 수 있나요?

upsertMongoDB는 MongoDB를 사용합니다. 때 추가 해 주세요.update() ★★★★★★★★★★★★★★{upsert:true} §:

key = {'key':'value'}
data = {'key2':'value2', 'key3':'value3'};
coll.update(key, data, upsert=True); #In python upsert must be passed as a keyword argument

이것으로 if-find-else-update 블록이 완전히 대체됩니다.키가 없으면 삽입되고 키가 있으면 업데이트됩니다.

이전:

{"key":"value", "key2":"Ohai."}

그 후:

{"key":"value", "key2":"value2", "key3":"value3"}

쓸 데이터를 지정할 수도 있습니다.

data = {"$set":{"key2":"value2"}}

.key2른른른

부터는 MongoDB 2.4를 할 수 .$setOnInsert(http://docs.mongodb.org/manual/reference/operator/setOnInsert/)

★★insertion_date를 사용합니다.$setOnInsert ★★★★★★★★★★★★★★★★★」last_update_date를 사용합니다.$set 안에서upsert명령어를 입력합니다.

의사 코드를 동작 예시로 변환하려면 다음 절차를 수행합니다.

now = datetime.utcnow()
for document in update:
    collection.update_one(
        filter={
            '_id': document['_id'],
        },
        update={
            '$setOnInsert': {
                'insertion_date': now,
            },
            '$set': {
                'last_update_date': now,
            },
        },
        upsert=True,
    )

항상 고유한 인덱스를 만들 수 있으며 이로 인해 MongoDB는 충돌하는 저장을 거부합니다.mongodb 쉘을 사용하여 다음 작업을 수행합니다.

> db.getCollection("test").insert ({a:1, b:2, c:3})
> db.getCollection("test").find()
{ "_id" : ObjectId("50c8e35adde18a44f284e7ac"), "a" : 1, "b" : 2, "c" : 3 }
> db.getCollection("test").ensureIndex ({"a" : 1}, {unique: true})
> db.getCollection("test").insert({a:2, b:12, c:13})      # This works
> db.getCollection("test").insert({a:1, b:12, c:13})      # This fails
E11000 duplicate key error index: foo.test.$a_1  dup key: { : 1.0 }

Upsert와 함께 .$setOnInsert환입니니다다

db.Table.update({noExist: true}, {"$setOnInsert": {xxxYourDocumentxxx}}, {upsert: true})

mongodb는 이런 종류의 선택적 상승은 지원하지 않는 것 같다.LeMiz와 같은 문제가 있어 'created' 타임스탬프와 'updated' 타임스탬프 모두 update(기준, newObj, upsert, multi)를 사용해도 제대로 작동하지 않습니다.다음 upstate 스테이트먼트를 나타냅니다.

update( { "name": "abc" }, 
        { $set: { "created": "2010-07-14 11:11:11", 
                  "updated": "2010-07-14 11:11:11" }},
        true, true ) 

시나리오 #1 - 'name'이 'abc'인 문서가 존재하지 않습니다.새 문서는 'name' = 'created', 'created' = 2010-07-14 11:11:11 및 'created' = 2010-07-14 11:11:11로 생성됩니다.

시나리오 #2 - '이름'이 '이름'인 문서가 '이름' = '이름', '작성' = 2010-07-12 09:09:09 및 '이름' = 2010-07-13 10:10:10과 함께 이미 존재합니다.상승 후 문서는 시나리오 #1의 결과와 동일합니다.삽입할 경우 설정할 필드와 갱신할 경우 남겨둘 필드를 UPS에서 지정할 수 없습니다.

저의 솔루션은 critera 필드에 고유한 인덱스를 만들고 삽입을 수행한 후 바로 'updated' 필드에서만 업데이트를 수행하는 것이었습니다.

1. Update를 사용합니다.

위의 Van Nguyen의 답변을 참고하여 저장 대신 업데이트를 사용하십시오.그러면 upsert 옵션에 액세스할 수 있습니다.

메모: 이 메서드는 발견 시 문서 전체를 덮어씁니다(문서 참조).

var conditions = { name: 'borne' }   , update = { $inc: { visits: 1 }} , options = { multi: true };

Model.update(conditions, update, options, callback);

function callback (err, numAffected) {   // numAffected is the number of updated documents })

1.a. $set 사용

문서 전체를 업데이트하지 않고 선택한 문서를 업데이트하려면 $set 메서드를 업데이트와 함께 사용할 수 있습니다.(다시, 의사로부터)...그래서, 만약 당신이 설정을 원한다면...

var query = { name: 'borne' };  Model.update(query, ***{ name: 'jason borne' }***, options, callback)

다음 이름으로 보내기...

Model.update(query, ***{ $set: { name: 'jason borne' }}***, options, callback)

하면 모든 것을 할 수 .{ name: 'jason borne' }.

요약

  • 기존 레코드 컬렉션이 있습니다.
  • 기존 레코드에 대한 업데이트를 포함하는 세트 레코드가 있습니다.
  • 일부 업데이트는 실제로 아무것도 업데이트하지 않고 기존 업데이트와 중복됩니다.
  • 모든 업데이트에는 이미 존재하는 동일한 필드가 포함되어 있으며 값이 다를 수 있습니다.
  • 레코드가 마지막으로 변경된 시간과 실제로 값이 변경된 위치를 추적하려고 합니다.

참고로, PyMongo는 당신이 선택한 언어에 맞게 바꿀 수 있다고 가정합니다.

순서:

  1. 중복 레코드가 발생하지 않도록 unique=true인 인덱스를 사용하여 컬렉션을 만듭니다.

  2. 입력 레코드에 대해 반복하여 15,000개 정도의 레코드 배치를 만듭니다.배치에 포함된 각 레코드에 대해 삽입할 데이터로 구성된 딕트를 만듭니다. 각 레코드는 새 레코드라고 가정합니다.'created' 및 'updated' 타임스탬프를 추가합니다.이것을 'ContinueOnError' 플래그=true와 함께 배치 삽입 명령으로 발행하면 중복된 키가 있더라도 다른 모든 항목이 삽입됩니다.이 작업은 매우 빠르게 진행될 것입니다.대량 삽입으로 15k/초의 성능을 얻을 수 있습니다.Continue On Error에 대한 자세한 내용은 http://docs.mongodb.org/manual/core/write-operations/를 참조하십시오.

    레코드 삽입은 매우 빠르게 이루어지므로 삽입은 순식간에 완료됩니다.이제 관련 기록을 갱신할 시간입니다.이 작업은 일괄 취득으로 한번에1개보다 훨씬 고속으로 실행할 수 있습니다.

  3. 모든 입력 레코드에 대해 다시 반복하여 15K 정도의 배치를 만듭니다.키를 추출합니다(키가 1개 있는 경우는 최적이지만 없는 경우는 어쩔 수 없습니다).db.collectionNameBlah.find({ 필드: { $in : [ 1, 2, 3 ... }) 쿼리를 사용하여 이 레코드 묶음을 Mongo에서 가져옵니다.이러한 각 레코드에 대해 업데이트가 있는지 확인하고, 업데이트가 있는 경우 '업데이트된' 타임스탬프 업데이트를 포함하여 업데이트를 발행합니다.

    유감스럽게도 MongoDB 2.4 이하에는 일괄 갱신 조작이 포함되어 있지 않습니다.그들은 그것에 대해 연구하고 있어요

주요 최적화 포인트:

  • 삽입물을 사용하면 대량 작업 속도가 크게 향상됩니다.
  • 기록을 일괄적으로 검색하면 작업 속도도 빨라집니다.
  • 현재는 개개의 갱신이 유일한 루트이지만, 10Gen이 대응하고 있습니다.아마 2.6일 것입니다만, 그때까지 완성될지 어떨지는 모르겠습니다만, 할 일이 많이 있습니다(그들의 Jira 시스템을 따르고 있습니다).

일반적으로 업데이트를 사용하는 것이 MongoDB에서 더 좋습니다. Python 어댑터로 어떻게 작업해야 할지 잘 모르겠습니다.

둘째, 해당 문서가 존재하는지 여부만 알 필요가 있는 경우에는 숫자만 반환하는 count()가 MongoDB에서 문서 전체를 전송하는 find_one보다 더 나은 옵션이 됩니다.

Pymongo의 방법

파이썬용 공식 MongoDB 드라이버

업데이트 및 덮어쓰기를 원할 수 있는 횟수의 5%는 새로운 행을 삽입하고 싶을 때 다음과 같이 처리됩니다.updateOne그리고.upsert

  • 기록의 95%(최소)는 매일 수정되지 않습니다.

핵심 mongoDB 기능에서 다음 솔루션을 얻을 수 있습니다.

db.collection.updateOne(filter, update, options)

필터를 기반으로 컬렉션 내의 단일 문서를 업데이트합니다.

이것은 이 Pymongo의 기능으로 이루어집니다.

코드 예:

# importing pymongo's MongoClient
from pymongo import MongoClient
 
conn = MongoClient('localhost', 27017)
db = conn.databaseName
 
# Filter by appliances called laptops
filter = { 'user_id': '4142480', 'question_id': '2801008' }
 
# Update number of laptops to
new_values = { "$set": { 'votes': 1400 } }
 
# Using update_one() method for single update with upsert.
db.collectionName.update_one(filter, new_values, upsert=True)

뭐?upsert=True하라고요?

  • 필터와 일치하는 문서가 없는 경우 새 문서를 만듭니다.
  • 필터와 일치하는 단일 문서를 업데이트합니다.

나는 지금 wait를 사용할 것을 제안합니다.

언급URL : https://stackoverflow.com/questions/2801008/mongodb-insert-if-not-exists

반응형