문서 배열의 개체를 업데이트하려면 어떻게 해야 합니까(내포된 업데이트)
다음과 같은 컬렉션이 있다고 가정해 보겠습니다.이것에 대해서는 몇 가지 질문이 있습니다.
{
"_id" : ObjectId("4faaba123412d654fe83hg876"),
"user_id" : 123456,
"total" : 100,
"items" : [
{
"item_name" : "my_item_one",
"price" : 20
},
{
"item_name" : "my_item_two",
"price" : 50
},
{
"item_name" : "my_item_three",
"price" : 30
}
]
}
"item_name":"my_item_two"의 가격을 올리고 싶은데, 없으면 "items" 배열에 추가해야 합니다.
두 필드를 동시에 업데이트하려면 어떻게 해야 합니까?예를 들어, "my_item_three"의 가격을 인상함과 동시에 "total"(같은 값)을 인상합니다.
저는 이것을 MongoDB측에서 하는 것을 선호합니다.그렇지 않으면 클라이언트측(Python)에서 문서를 로드하고 업데이트된 문서를 작성하여 MongoDB의 기존 문서로 교체해야 합니다.
이것은 내가 시도했던 것으로, 오브젝트가 존재하는 경우 정상적으로 동작합니다.
db.test_invoice.update({user_id : 123456 , "items.item_name":"my_item_one"} , {$inc: {"items.$.price": 10}})
그러나 키가 존재하지 않으면 아무 것도 하지 않습니다.또한 중첩된 개체만 업데이트합니다.이 명령어에서는 "total" 필드도 갱신할 수 없습니다.
1번 문제는 두 부분으로 나눠보도록 하겠습니다.먼저 "items.item_name"이 "my_item_two"와 동일한 문서를 늘립니다.이를 위해서는 "$" 위치 연산자를 사용해야 합니다.예를 들어 다음과 같습니다.
db.bar.update( {user_id : 123456 , "items.item_name" : "my_item_two" } ,
{$inc : {"items.$.price" : 1} } ,
false ,
true);
이렇게 하면 어레이 내의 첫 번째 일치하는 하위 문서만 증가합니다(따라서 "item_name"이 "my_item_two"와 동일한 다른 문서가 어레이 내에 있는 경우 증가하지 않습니다).하지만 이게 네가 원하는 것일 수도 있어.
2부가 더 까다로워.다음과 같이 "my_item_two"를 사용하지 않고 새 항목을 배열에 푸시할 수 있습니다.
db.bar.update( {user_id : 123456, "items.item_name" : {$ne : "my_item_two" }} ,
{$addToSet : {"items" : {'item_name' : "my_item_two" , 'price' : 1 }} } ,
false ,
true);
2번 문제는 정답이 더 쉬워요."my_item_3"이 포함된 문서에서 item_3의 합계 및 가격을 증가시키려면 여러 필드에서 $inc 연산자를 동시에 사용할 수 있습니다.예를 들어 다음과 같습니다.
db.bar.update( {"items.item_name" : {$ne : "my_item_three" }} ,
{$inc : {total : 1 , "items.$.price" : 1}} ,
false ,
true);
단일 쿼리에서는 이 작업을 수행할 수 없습니다.첫 번째 쿼리에서 문서를 검색해야 합니다.
문서가 존재하는 경우:
db.bar.update( {user_id : 123456 , "items.item_name" : "my_item_two" } ,
{$inc : {"items.$.price" : 1} } ,
false ,
true);
또 다른
db.bar.update( {user_id : 123456 } ,
{$addToSet : {"items" : {'item_name' : "my_item_two" , 'price' : 1 }} } ,
false ,
true);
조건을 추가할 필요가 없습니다.{$ne : "my_item_two" }.
또한 멀티스레드 환경에서는 한 번에 1개의 스레드만 두 번째 스레드(문서를 찾을 수 없는 경우 케이스 삽입)를 실행할 수 있도록 주의해야 합니다.그렇지 않으면 중복된 삽입 문서가 삽입됩니다.
연산자를 사용하여 개체 내부의 중첩된 배열을 업데이트할 수 있습니다. 값을 업데이트하십시오.
db.getCollection('geolocations').update(
{
"_id" : ObjectId("5bd3013ac714ea4959f80115"),
"geolocation.country" : "United States of America"
},
{ $set:
{
"geolocation.$.country" : "USA"
}
},
false,
true
);
"item_name" 필드가 중복되지 않도록 하는 한 가지 방법은 질문 #1에 대한 답변 https://stackoverflow.com/a/10523963에서 지정한 것과 동일한 작업을 역순으로 수행하는 것입니다.
- "items.item_name"의 경우 문서를 누릅니다.{"$ne":"my_name"} - 업데이트 필터에 고유 색인 필드가 포함되어 있어야 합니다.그리고 상승은 거짓이다.
- "items.item_name":"my_name"인 경우 문서를 늘립니다.
첫 번째 업데이트는 atomic이어야 합니다.따라서 배열에 item_name "my_name"이라는 이름의 요소가 이미 포함되어 있는 경우에는 아무것도 수행하지 않습니다.
두 번째 업데이트가 발생할 때까지 "item_name"="my_name"을 가진 어레이 요소가 있어야 합니다.
언급URL : https://stackoverflow.com/questions/10522347/how-do-you-update-objects-in-a-documents-array-nested-updating
'source' 카테고리의 다른 글
| Angular에서 함수 호출같은 서비스의 JS 서비스? (0) | 2023.03.04 |
|---|---|
| 부울값을 React의 소품으로 전달할 수 없는 이유는 항상 내 코드에 문자열이 전달되어야 하기 때문입니다. (0) | 2023.03.04 |
| 캔버스 및 각도 작업JS (0) | 2023.03.04 |
| 컴포넌트를 확장/상속하는 방법 (0) | 2023.03.04 |
| mongorestore 오류:덤프 파일을 어떻게 해야 할지 모르겠어요. (0) | 2023.03.04 |