mongodb에서 여러 어레이 요소를 업데이트하는 방법
저는 여러 가지 요소가 들어 있는 몽고 문서를 가지고 있습니다.
싶다.handled
내 . 여기서 "는 다음과 같습니다..profile
= XX.
이 문서의 형식은 다음과 같습니다.
{
"_id": ObjectId("4d2d8deff4e6c1d71fc29a07"),
"user_id": "714638ba-2e08-2168-2b99-00002f3d43c0",
"events": [{
"handled": 1,
"profile": 10,
"data": "....."
} {
"handled": 1,
"profile": 10,
"data": "....."
} {
"handled": 1,
"profile": 20,
"data": "....."
}
...
]
}
그래서 저는 다음을 시도했습니다.
.update({"events.profile":10},{$set:{"events.$.handled":0}},false,true)
단, 각 문서의 첫 번째 일치 어레이 요소만 갱신합니다.(이것은 positional 연산자 $에 대해 정의된 동작입니다.)
일치하는 어레이 요소를 모두 업데이트하려면 어떻게 해야 합니까?
MongoDB 3.6 릴리즈(및 MongoDB 3.5.12의 개발 브랜치에서 이용 가능)를 통해 한 번의 요청으로 여러 어레이 요소를 업데이트할 수 있게 되었습니다.
여기에는 이 버전에서 도입된 필터링된 위치 업데이트 연산자 구문이 사용됩니다.
db.collection.update(
{ "events.profile":10 },
{ "$set": { "events.$[elem].handled": 0 } },
{ "arrayFilters": [{ "elem.profile": 10 }], "multi": true }
)
"arrayFilters"
as passed to options for or even, 또는 method는 업데이트스테이트먼트에서 지정된ID와 대조하는 조건을 지정합니다.지정된 조건과 일치하는 요소가 모두 업데이트됩니다.
점에 주의:"multi"
질문의 맥락에서 주어진 바와 같이, "복수의 요소를 갱신할 것"이라는 예상에서 사용되었지만, 이는 그렇지 않았고 지금도 그렇지 않다.여기서의 용도는 지금까지와 같이 "복수 문서"에 적용되거나 최신 API 버전에서 필수 설정으로 지정되었습니다.
비고 아이러니하게도, 이것은 다음에 대한 "옵션" 인수에 명시되어 있기 때문이다.
.update()
또한 메서드와 마찬가지로 구문은 일반적으로 최신 릴리스 드라이버 버전과 호환됩니다.이것은 .
mongo
되어 있기 도 「 「」( 「하위 호환성을 위해서」).arrayFilters
및과의 " 호환성" 및 "레거시" MongoDB를 제공하기 않습니다..update()
API 콜 api,
mongo
셸 또는 기타 "쉘 기반" 제품(특히 Robo 3T )은 3.6 이상의 개발 지점 또는 프로덕션 릴리스에서 최신 버전이 필요합니다.
또, 「복수의 어레이 요소」를 갱신하고 있습니다만, 지정된 조건에는 적용하지 않고, 그것이 필요한 어레이내의 모든 요소에 적용되는 것도 참조해 주세요.
또, 「어레이가 다른 어레이내에 있는」어레이 구조에 이러한 새로운 포지셔닝 연산자를 적용하는 방법에 대해서는, 「MongoDB 에 의한 네스트 어레이의 갱신」을 참조해 주세요.
중요 - 이전 버전에서 업그레이드된 설치로 인해 MongoDB 기능이 활성화되지 않았을 수 있으며, 이로 인해 문장이 실패할 수도 있습니다.업그레이드 절차가 인덱스 업그레이드와 같은 세부 정보와 함께 완료되었는지 확인한 후 실행해야 합니다.
db.adminCommand( { setFeatureCompatibilityVersion: "3.6" } )
설치되어 있는 하는 상위 "예: "예" "예: "예" "예" "예" "예" "예" "예" "예" "예" "예" "예" "예" "예" "예" "예" "예" "예"
"4.0"
4번으로 하다이를 통해 새로운 위치 업데이트 연산자 등의 기능이 활성화되었습니다.하다db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )
현재 설정을 반환하려면
갱신: Mongo version 3.6 이후, 이 답변은 언급된 문제가 수정되었고 이를 달성할 수 있는 방법이 있기 때문에 더 이상 유효하지 않습니다.다른 답변을 확인해 주세요.
현재 위치 연산자를 사용하여 배열의 모든 항목을 업데이트할 수 없습니다.JIRA http://jira.mongodb.org/browse/SERVER-1243 를 참조해 주세요.
다음과 같은 작업을 할 수 있습니다.
- 각 항목을 개별적으로 업데이트합니다(events.0.handled events.1.handled...) 또는...
- 문서를 읽고 수동으로 편집한 후 이전 문서를 대체하여 저장합니다(원자성 업데이트를 확인하려면 "현재 업데이트" 선택).
나에게 효과가 있었던 것은, 다음과 같다.
db.collection.find({ _id: ObjectId('4d2d8deff4e6c1d71fc29a07') })
.forEach(function (doc) {
doc.events.forEach(function (event) {
if (event.profile === 10) {
event.handled=0;
}
});
db.collection.save(doc);
});
mongo newbies나 JQuery & friends에 익숙한 사람이라면 더 명확할 것 같습니다.
또한 업데이트되지 않은 하위 문서가 남아 있는 문서가 있는지 확인하는 while loop을 사용하여 이 작업을 수행할 수도 있습니다.이 방법은 업데이트의 원자성을 보존합니다(여기에 있는 다른 많은 솔루션에는 해당되지 않음).
var query = {
events: {
$elemMatch: {
profile: 10,
handled: { $ne: 0 }
}
}
};
while (db.yourCollection.find(query).count() > 0) {
db.yourCollection.update(
query,
{ $set: { "events.$.handled": 0 } },
{ multi: true }
);
}
.profile
및 10 킬로와 .handled
0이 아닌 값은 컬렉션의 모든 문서에서 발생합니다.가 있고 그 중 에 100개의 문서와 문서가 있는 query
다른 모든 문서에는 일치하는 하위 문서가 적습니다. 3번입니다.
이 방법을 사용하면 이 스크립트가 실행되는 동안 다른 프로세스에 의해 갱신될 수 있는 다른 데이터가 클로버되는 위험을 피할 수 있습니다.또, 클라이언트와 서버간에 전송되는 데이터의 양도 최소한으로 억제합니다.
이는 http://jira.mongodb.org/browse/SERVER-1243의 장기간에 걸친 문제와 관련이 있습니다.여러 어레이가 일치하는 경우 "모든 케이스"를 지원하는 명확한 구문에 많은 문제가 있습니다.실제로 이 문제에 대한 해결책으로 "지원"하는 방법이 이미 있습니다.예를 들어, 본 게시물 이후에 실시된 대량 작업 등이 있습니다.
하나의 업데이트 스테이트먼트에서 일치하는 어레이 요소를 여러 개 업데이트할 수 없기 때문에 "멀티" 업데이트를 해도 해당 단일 스테이트먼트의 각 문서에 대해 어레이 내의 하나의 매트 요소만 업데이트할 수 있습니다.
현시점에서는 일치하는 모든 문서를 검색하여 루프하고 일괄 업데이트를 처리하는 것이 최선의 해결책입니다.이것에 의해, 적어도 많은 조작을 1개의 요구로 송신할 수 있어 단일의 응답은 1개입니다.필요에 따라 를 사용하여 검색 결과에 반환되는 어레이 콘텐츠를 업데이트 선택 조건과 일치하는 콘텐츠로만 줄일 수 있습니다.
db.collection.aggregate([
{ "$match": { "events.handled": 1 } },
{ "$project": {
"events": {
"$setDifference": [
{ "$map": {
"input": "$events",
"as": "event",
"in": {
"$cond": [
{ "$eq": [ "$$event.handled", 1 ] },
"$$el",
false
]
}
}},
[false]
]
}
}}
]).forEach(function(doc) {
doc.events.forEach(function(event) {
bulk.find({ "_id": doc._id, "events.handled": 1 }).updateOne({
"$set": { "events.$.handled": 0 }
});
count++;
if ( count % 1000 == 0 ) {
bulk.execute();
bulk = db.collection.initializeOrderedBulkOp();
}
});
});
if ( count % 1000 != 0 )
bulk.execute();
.aggregate()
이 부분은 어레이의 "정확한" 식별자가 있거나 각 요소의 모든 콘텐츠가 "정확한" 요소 자체를 형성할 때 작동합니다.이것은, 의 「set」연산자가, 다음의 어느쪽인가를 필터링 하기 위해서 사용되고 있기 때문입니다.false
배열을 처리하는 데 사용된 작업에서 반환된 값입니다.
어레이 콘텐츠에 고유한 요소가 없는 경우 를 사용하여 대체 방법을 시도할 수 있습니다.
db.collection.aggregate([
{ "$match": { "events.handled": 1 } },
{ "$redact": {
"$cond": {
"if": {
"$eq": [ { "$ifNull": [ "$handled", 1 ] }, 1 ]
},
"then": "$$DESCEND",
"else": "$$PRUNE"
}
}}
])
다만, 실제로는 다른 문서 레벨에 존재하는 필드인 경우, 예기치 않은 결과를 얻을 가능성이 높지만, 그 필드가 하나의 문서 위치에만 표시되어 동등하게 일치하는 경우에는 문제가 없습니다.
출시(의 "(3.1 MongoDB)",$filter
다다심심심::
db.collection.aggregate([
{ "$match": { "events.handled": 1 } },
{ "$project": {
"events": {
"$filter": {
"input": "$events",
"as": "event",
"cond": { "$eq": [ "$$event.handled", 1 ] }
}
}
}}
])
, 「」를 서포트하는 ..aggregate()
에서는 다음과 같은 접근방식을 사용할 수 있지만 이 연산자를 사용하면 파이프라인에서의 어레이 확장으로 인해 효율성이 가장 떨어집니다.
db.collection.aggregate([
{ "$match": { "events.handled": 1 } },
{ "$unwind": "$events" },
{ "$match": { "events.handled": 1 } },
{ "$group": {
"_id": "$_id",
"events": { "$push": "$events" }
}}
])
MongoDB 버전이 집약 출력에서 "cursor"를 지원하는 모든 경우, 이는 접근 방식을 선택하고 일괄 업데이트 문을 처리하기 위해 표시된 것과 동일한 코드 블록을 사용하여 결과를 반복하는 문제일 뿐입니다.집약 출력으로부터의 벌크 조작과 「커서」는, 같은 버전(MongoDB 2.6)으로 도입되어 있기 때문에, 통상은 함께 처리됩니다.
에서도 아마 것입니다..find()
가 됩니다..update()
★★★★
db.collection.find({ "events.handled": 1 }).forEach(function(doc){
doc.events.filter(function(event){ return event.handled == 1 }).forEach(function(event){
db.collection.update({ "_id": doc._id },{ "$set": { "events.$.handled": 0 }});
});
});
「다중」업데이트를 실시하기로 결정했을 경우, 또는 일치하는 문서 마다 복수의 갱신을 처리하는 것보다 최종적으로 효율적이라고 판단했을 경우는, 가능한 어레이의 최대수를 항상 판단해, 갱신할 문서가 없어질 때까지, 복수의 갱신을 실행할 수 있습니다.
4및 2.2 에 대한 에서는 MongoDB 2.4 2.2 버전을 사용할 ..aggregate()
: " "을 참조하십시오.
var result = db.collection.aggregate([
{ "$match": { "events.handled": 1 } },
{ "$unwind": "$events" },
{ "$match": { "events.handled": 1 } },
{ "$group": {
"_id": "$_id",
"count": { "$sum": 1 }
}},
{ "$group": {
"_id": null,
"count": { "$max": "$count" }
}}
]);
var max = result.result[0].count;
while ( max-- ) {
db.collection.update({ "events.handled": 1},{ "$set": { "events.$.handled": 0 }},{ "multi": true })
}
어떤 경우에도 업데이트 중에 하지 않는 것이 있습니다.
어레이를 "원샷"으로 업데이트하지 마십시오.어레이 콘텐츠 전체를 코드로 업데이트하고 그 다음 업데이트 하는 것이 더 효율적이라고 생각되는 경우
$set
각 문서의 전체 어레이를 표시합니다.이 작업이 더 빠르게 처리되는 것처럼 보일 수 있지만 어레이 내용을 읽고 업데이트를 수행한 후 변경되지 않았음을 보장하지는 않습니다.$set
는 아직 atomic 연산자이기 때문에 올바른 데이터로 어레이를 갱신할 뿐입니다.따라서 읽기 및 쓰기 사이에 발생하는 변경은 덮어쓸 가능성이 있습니다.업데이트할 인덱스 값 계산 안 함:"원샷" 접근 방식과 유사한 경우 해당 위치만 파악하면 됩니다.
0
포지션 ★★★2
은 및 이며, 다음과 같은 ( ) 、 것 、 것 、 음 、 음 、 음 、 음 、 음 、 음 、 음 음 、 음 음 음 음 。{ "$set": { "events.0.handled": 0, "events.2.handled": 0 }}
여기서도 문제는 문서를 읽을 때 발견된 인덱스 값이 업데이트 시 배열에서 동일한 인덱스 값이라고 가정하는 것입니다.순서를 변경하는 방법으로 어레이에 새로운 아이템을 추가하면 그 위치는 무효가 되어 잘못된 아이템이 갱신됩니다.
따라서 일치하는 어레이 요소를 1개의 업데이트 스테이트먼트 내에서 처리할 수 있는 적절한 구문이 결정될 때까지 기본 접근법은 일치하는 어레이 요소를 개별적으로 업데이트하거나(이상적으로 일괄적으로) 더 이상 업데이트하지 않을 때까지 최대 어레이 요소를 계산하는 것입니다.수정된 결과가 반환됩니다.어쨌든 일치하는 어레이 요소에서 위치 업데이트를 "항상" 처리해야 합니다. 이는 스테이트먼트당 하나의 요소만 업데이트하는 경우에도 마찬가지입니다.
벌크 오퍼레이션은 사실 '복수 오퍼레이션'으로 판명된 모든 오퍼레이션을 처리하는 '범용' 솔루션입니다.또, 같은 값의 복수의 어레이 요소를 갱신하는 것 이상의 애플리케이션이 있기 때문에, 물론 이미 실장되어 있기 때문에, 현시점에서는, 이 문제를 해결하기 위한 최선의 어프로치입니다.
첫째: 위치 연산자를 사용 중이어서 코드가 작동하지 않았습니다.$
어레이 내에서 갱신할 요소만 식별할 뿐 어레이 내에서의 위치조차 명시적으로 지정하지 않습니다.
연산자 입니다.$[<identifier>]
어레이 필터 조건에 일치하는 모든 요소가 업데이트됩니다.
솔루션:
db.collection.update({"events.profile":10}, { $set: { "events.$[elem].handled" : 0 } },
{
multi: true,
arrayFilters: [ { "elem.profile": 10 } ]
})
코드 기능:
{"events.profile":10}
는 컬렉션을 합니다.$set
operator: 합니다.update operator: "업데이트" operator: "업데이트 。{multi:true}
은 만들이 된다..update()
하는 모든 하여 "필터 사용 시"와 같이 동작은 '필터'입니다.updateMany()
{ "events.$[elem].handled" : 0 } and arrayFilters: [ { "elem.profile": 10 } ]
array Filters fil position 。여기에 배열이 있습니다.$[elem]
는 배열 필터에 지정된 조건에 일치하는 배열 필드의 모든 요소에 대한 자리 표시자 역할을 합니다.
MongoDB의 모든 요소를 업데이트할 수 있습니다.
db.collectioname.updateOne(
{ "key": /vikas/i },
{ $set: {
"arr.$[].status" : "completed"
} }
)
"arr" 어레이의 모든 "status" 값이 "completed"로 업데이트됩니다.
하나의 문서만 있는 경우
db.collectioname.updateOne(
{ key:"someunique", "arr.key": "myuniq" },
{ $set: {
"arr.$.status" : "completed",
"arr.$.msgs": {
"result" : ""
}
} }
)
그러나 배열 내의 모든 문서를 업데이트하지 않으려면 요소를 통과하여 if 블록 내에서 루프해야 합니다.
db.collectioname.find({findCriteria })
.forEach(function (doc) {
doc.arr.forEach(function (singlearr) {
if (singlearr check) {
singlearr.handled =0
}
});
db.collection.save(doc);
});
아직도 몽고어로 다루지 않은게 신기하네요.서브어레이를 다룰 때 몽고는 전체적으로 좋지 않은 것 같습니다.예를 들어, 하위 배열은 단순히 셀 수 없습니다.
하비에르의 첫 번째 해결책을 사용했어배열을 이벤트로 읽고 루프 통과하여 set exp:
var set = {}, i, l;
for(i=0,l=events.length;i<l;i++) {
if(events[i].profile == 10) {
set['events.' + i + '.handled'] = 0;
}
}
.update(objId, {$set:set});
이는 조건부 테스트를 위한 콜백을 사용하여 함수로 요약할 수 있습니다.
스레드는 매우 오래되었지만, 저는 여기에 답을 찾으러 왔기 때문에 새로운 솔루션을 제공합니다.
MongoDB 버전 3.6+에서는 위치 연산자를 사용하여 배열 내의 모든 항목을 업데이트할 수 있습니다.공식 문서는 여기를 참조하십시오.
여기서 묻는 질문에는 다음 쿼리를 사용할 수 있습니다.Java-MongoDB 드라이버도 확인했습니다만, 정상적으로 동작합니다.
.update( // or updateMany directly, removing the flag for 'multi'
{"events.profile":10},
{$set:{"events.$[].handled":0}}, // notice the empty brackets after '$' opearor
false,
true
)
이게 나 같은 사람에게 도움이 됐으면 좋겠어.
저는 C# 3.6용 최신 드라이버를 사용하여 이 문제를 해결하려고 했습니다.결국 이 문제를 해결했습니다.여기서의 키는 "$[]"를 사용하는데, MongoDB는 버전 3.6에서 새로워졌다고 합니다.상세한 것에 대하여는, https://docs.mongodb.com/manual/reference/operator/update/positional-all/ #up.S[ ]를 참조해 주세요.
코드는 다음과 같습니다.
{
var filter = Builders<Scene>.Filter.Where(i => i.ID != null);
var update = Builders<Scene>.Update.Unset("area.$[].discoveredBy");
var result = collection.UpdateMany(filter, update, new UpdateOptions { IsUpsert = true});
}
자세한 내용은 MongoDB C# 드라이버를 사용하여 모든 문서에서 어레이 요소를 삭제하십시오.
$[] 연산자는 중첩된 모든 어레이를 선택합니다.모든 어레이 항목을 '$[]'로 업데이트할 수 있습니다.
.update({"events.profile":10},{$set:{"events.$[].handled":0}},false,true)
이 스레드에서 $[] 사용을 제안하는 일부 답변이 올바르지 않습니다.
db.collection.update(
{"events.profile":10},
{$set:{"events.$[].handled":0}},
{multi:true}
)
위의 코드는 "프로파일" 값에 관계없이 "이벤트" 배열의 모든 요소에 대해 "처리됨"을 0으로 업데이트합니다. " "{"events.profile":10}
는 문서 전체를 필터링하는 것일 뿐 배열 내의 문서는 필터링하지 않습니다. 때는 꼭 해야 합니다.$[elem]
arrayFilters
닐 런
실제로 save 명령어는 Document 클래스의 인스턴스에만 있습니다.그것들은 많은 방법들과 속성들을 가지고 있다.따라서 line() 함수를 사용하여 작업 부하를 줄일 수 있습니다.여기를 참조해 주세요.https://hashnode.com/post/why-are-mongoose-mongodb-odm-lean-queries-faster-than-normal-queries-cillvawhq0062kj53asxoyn7j
저장 기능의 또 다른 문제로 동시에 다중 저장과 충돌 데이터가 발생합니다.Model.Update는 데이터를 일관되게 만듭니다.문서 배열의 여러 항목을 업데이트합니다.익숙한 프로그래밍 언어를 사용하여 다음과 같은 것을 시도해 보십시오. 저는 mongoose를 사용합니다.
User.findOne({'_id': '4d2d8deff4e6c1d71fc29a07'}).lean().exec()
.then(usr =>{
if(!usr) return
usr.events.forEach( e => {
if(e && e.profile==10 ) e.handled = 0
})
User.findOneAndUpdate(
{'_id': '4d2d8deff4e6c1d71fc29a07'},
{$set: {events: usr.events}},
{new: true}
).lean().exec().then(updatedUsr => console.log(updatedUsr))
})
mongo db의 여러 문서에서 어레이 필드를 업데이트합니다.
mongoDb의 어레이 요소를 업데이트하려면 update many 쿼리와 함께 $pull 또는 $push를 사용합니다.
Notification.updateMany(
{ "_id": { $in: req.body.notificationIds } },
{
$pull: { "receiversId": req.body.userId }
}, function (err) {
if (err) {
res.status(500).json({ "msg": err });
} else {
res.status(200).json({
"msg": "Notification Deleted Successfully."
});
}
});
어레이 내의 어레이를 갱신하는 경우
await Booking.updateOne(
{
userId: req.currentUser?.id,
cart: {
$elemMatch: {
id: cartId,
date: date,
//timeSlots: {
//$elemMatch: {
//id: timeSlotId,
//},
//},
},
},
},
{
$set: {
version: booking.version + 1,
'cart.$[i].timeSlots.$[j].spots': spots,
},
},
{
arrayFilters: [
{
'i.id': cartId,
},
{
'j.id': timeSlotId,
},
],
new: true,
}
);
다음을 시도해보니 잘 작동합니다.
.update({'events.profile': 10}, { '$set': {'events.$.handled': 0 }},{ safe: true, multi:true }, callback function);
// nodejs의 경우 콜백 함수
언급URL : https://stackoverflow.com/questions/4669178/how-to-update-multiple-array-elements-in-mongodb
'sourcecode' 카테고리의 다른 글
Jest 테스트 실패: TypeError: window.matchMedia가 함수가 아닙니다. (0) | 2023.03.19 |
---|---|
스프링 부트 셧다운 훅 (0) | 2023.03.19 |
빈 배열을 입력으로 사용하는 'useCallback'과 두 번째 매개 변수를 사용하지 않는 'useCallback'의 차이점은 무엇입니까? (0) | 2023.03.19 |
AngularJS: $resource 요청과 함께 인증 토큰을 보내려면 어떻게 해야 합니까? (0) | 2023.03.19 |
Woocommerce에서 판매 중인 제품에 "세일" 제품 카테고리 추가 (0) | 2023.03.19 |