Cách cập nhật nhiều phần tử mảng trong mongodb


183

Tôi có một tài liệu Mongo chứa một loạt các yếu tố.

Tôi muốn đặt lại .handledthuộc tính của tất cả các đối tượng trong mảng trong đó .profile= XX.

Tài liệu này ở dạng sau:

{
    "_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": "....."
        }
        ...
    ]
}

Vì vậy, tôi đã thử như sau:

.update({"events.profile":10},{$set:{"events.$.handled":0}},false,true)

Tuy nhiên, nó chỉ cập nhật phần tử mảng phù hợp đầu tiên trong mỗi tài liệu. (Đó là hành vi được xác định cho $ - toán tử vị trí .)

Làm thế nào tôi có thể cập nhật tất cả các yếu tố mảng phù hợp?


2
Cập nhật một tập hợp con hoặc tất cả các mục mảng đã được thêm vào mongodb 3.6: docs.mongodb.com/manual/reference/operator/update/ Lỗi
Jaap

hãy chắc chắn kiểm tra ArrayFilters và xem xét sử dụng truy vấn nào để cập nhật hiệu quả. Kiểm tra câu trả lời của Neil Lunn: stackoverflow.com/a/46054172/337401
Jaap

kiểm tra câu trả lời của tôi
Ucdemir

Câu trả lời:


111

Tại thời điểm này, không thể sử dụng toán tử vị trí để cập nhật tất cả các mục trong một mảng. Xem JIRA http://jira.mongodb.org/browse/SERVER-1243

Như một công việc xung quanh bạn có thể:

  • Cập nhật từng mục riêng lẻ (event.0.handled event.1.handled ...) hoặc ...
  • Đọc tài liệu, thực hiện các chỉnh sửa theo cách thủ công và lưu nó thay thế cái cũ hơn (kiểm tra "Cập nhật nếu hiện tại" nếu bạn muốn đảm bảo cập nhật nguyên tử)

15
nếu bạn gặp vấn đề tương tự, hãy bỏ phiếu cho vấn đề này - jira.mongodb.org/browse/SERVER-1243
LiorH

Tôi thực sự thích tài liệu đọc và lưu phương pháp tiếp cận. Nhưng tôi đã sử dụng Couch trước Mongo để cách tiếp cận đó có vẻ tự nhiên hơn vì không có API truy vấn cho Couch, chỉ là một api REST cho toàn bộ tài liệu
adam

1
Cả hai cách tiếp cận này đều đòi hỏi dung lượng bộ nhớ khá cao, phải không? Nếu có nhiều tài liệu phải tìm kiếm và phải tải tất cả chúng (hoặc các mảng lồng nhau) để cập nhật ... + cũng hơi rắc rối khi thực hiện nếu việc này phải được thực hiện không đồng bộ ...
Ixx

13
Tất cả các khó khăn kỹ thuật sang một bên, điều đáng ngạc nhiên là tính năng này không có sẵn trong MongoDB. Ràng buộc này lấy đi nhiều tự do từ việc tùy chỉnh lược đồ cơ sở dữ liệu.
Sung Cho

5
Neil Lunn stackoverflow.com/a/46054172/337401 đã trả lời điều này cho phiên bản 3.6. Vì đây là một câu hỏi phổ biến nên có thể đáng để cập nhật câu trả lời được chấp nhận này với lời giới thiệu cho câu trả lời của Neil Lunn.
Jaap

73

Với việc phát hành MongoDB 3.6 (và có sẵn trong nhánh phát triển từ MongoDB 3.5.12), giờ đây bạn có thể cập nhật nhiều phần tử mảng trong một yêu cầu.

Điều này sử dụng cú pháp toán tử cập nhật vị trí được lọc được$[<identifier>] giới thiệu trong phiên bản này:

db.collection.update(
  { "events.profile":10 },
  { "$set": { "events.$[elem].handled": 0 } },
  { "arrayFilters": [{ "elem.profile": 10 }], "multi": true }
)

Các "arrayFilters"như truyền cho các tùy chọn cho .update()hay thậm chí .updateOne(), .updateMany(), .findOneAndUpdate()hoặc .bulkWrite()quy định cụ thể phương pháp điều kiện để phù hợp trên định danh được đưa ra trong báo cáo cập nhật. Bất kỳ yếu tố phù hợp với điều kiện đưa ra sẽ được cập nhật.

Lưu ý rằng "multi"như được đưa ra trong bối cảnh của câu hỏi đã được sử dụng với hy vọng rằng điều này sẽ "cập nhật nhiều yếu tố" nhưng điều này không phải và vẫn không phải là trường hợp. Việc sử dụng ở đây áp dụng cho "nhiều tài liệu" như mọi khi hoặc được quy định khác là cài đặt bắt buộc .updateMany()trong các phiên bản API hiện đại.

LƯU Ý Hơi mỉa mai, vì điều này được chỉ định trong đối số "tùy chọn" cho.update() và giống như các phương thức, cú pháp thường tương thích với tất cả các phiên bản trình điều khiển phát hành gần đây.

Tuy nhiên, điều này không đúng với mongoshell, vì cách thức phương thức được triển khai ở đó ("trớ trêu thay cho khả năng tương thích ngược"), arrayFiltersđối số không được nhận ra và loại bỏ bởi một phương thức bên trong phân tích các tùy chọn để cung cấp "khả năng tương thích ngược" với trước Các phiên bản máy chủ MongoDB và .update()cú pháp gọi API "di sản" .

Vì vậy, nếu bạn muốn sử dụng lệnh trong mongoshell hoặc các sản phẩm "shell dựa" khác (đáng chú ý là Robo 3T), bạn cần một phiên bản mới nhất từ ​​nhánh phát triển hoặc bản phát hành sản xuất kể từ 3.6 trở lên.

Xem thêm cũng positional all $[]cập nhật "nhiều phần tử mảng" nhưng không áp dụng cho các điều kiện được chỉ định và áp dụng cho tất cả phần tử trong mảng có hành động mong muốn.

Đồng thời xem Cập nhật Mảng lồng nhau với MongoDB để biết cách các toán tử vị trí mới này áp dụng cho các cấu trúc mảng "lồng nhau", trong đó "mảng nằm trong các mảng khác".

QUAN TRỌNG - Các bản cài đặt được nâng cấp từ các phiên bản trước "có thể" chưa kích hoạt các tính năng MongoDB, điều này cũng có thể khiến các câu lệnh không thành công. Bạn nên đảm bảo quy trình nâng cấp của mình hoàn tất với các chi tiết như nâng cấp chỉ mục và sau đó chạy

   db.adminCommand( { setFeatureCompatibilityVersion: "3.6" } )

Hoặc phiên bản cao hơn như được áp dụng cho phiên bản đã cài đặt của bạn. tức là "4.0"cho phiên bản 4 trở đi hiện tại. Điều này cho phép các tính năng như các toán tử cập nhật vị trí mới và các tính năng khác. Bạn cũng có thể kiểm tra với:

   db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )

Để trả về cài đặt hiện tại


9
Câu trả lời được chấp nhận nên được cập nhật và tham khảo câu trả lời này.
Jaap

2
elem
dùng1063287

1
Chính xác. Lưu ý rằng RoboMongo chưa hỗ trợ arrayFilters, vì vậy hãy chạy cập nhật qua CLI. stackoverflow.com/questions/48322834/ từ
drlff

cảm ơn bạn, Neil, đặc biệt là phần QUAN TRỌNG, chính xác những gì tôi cần
janfabian

mã này trả về LRI trong pymongo. tehre là lỗi: tăng TypeError ("% s phải đúng hoặc sai"% (tùy chọn,)) TypeError: upsert phải đúng hoặc sai
Vagif

67

Điều làm việc cho tôi là thế này:

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);
  });

Tôi nghĩ rõ ràng hơn đối với người mới mongo và bất kỳ ai quen thuộc với JQuery và bạn bè.


Tôi đang sử dụng db.posts.find({ 'permalink':permalink }).forEach( function(doc) {...và tôi đang nhận đượcOops.. TypeError: Object # has no method 'forEach'
Squirrl

3
@Squirrl có thể là phiên bản mongodb lỗi thời? Tài liệu rõ ràng về cách áp dụng chức năng forEach trên một con trỏ nhưng không nêu rõ vì phiên bản nào được hỗ trợ. docs.mongodb.org/manual/reference/method/coder.forEach
Daniel Cerecedo

@Squirrl thửdb.posts.find(...).toArray().forEach(...)
marmor

Chúng ta không thể làm điều này mà không sử dụng Javascript? Tôi muốn thực hiện cập nhật này trực tiếp từ trình vỏ mongo mà không cần sử dụng API Javascript.
Meliodas

1
Bạn có thể vui lòng viết truy vấn này trong trình điều khiển mongodb cho java hoặc với spring-data-mongodb không? Cảm ơn, kris
chiku

18

Điều này cũng có thể được thực hiện với một vòng lặp while để kiểm tra xem có tài liệu nào còn tồn tại mà vẫn có các bản đồ con chưa được cập nhật hay không. Phương pháp này bảo tồn tính nguyên tử của các cập nhật của bạn (điều mà nhiều giải pháp khác ở đây không làm được).

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 }
    );
}

Số lần vòng lặp được thực thi sẽ bằng số lần tối đa số lần truy cập con profilebằng 10 và handledkhông bằng 0 xảy ra trong bất kỳ tài liệu nào trong bộ sưu tập của bạn. Vì vậy, nếu bạn có 100 tài liệu trong bộ sưu tập của mình và một trong số chúng có ba tài liệu con phù hợpquery và tất cả các tài liệu khác có ít tài liệu con phù hợp hơn, vòng lặp sẽ thực hiện ba lần.

Phương pháp này tránh được nguy cơ ghi đè dữ liệu khác có thể được cập nhật bởi một quy trình khác trong khi tập lệnh này thực thi. Nó cũng giảm thiểu lượng dữ liệu được truyền giữa máy khách và máy chủ.


13

Trên thực tế, điều này liên quan đến vấn đề tồn tại lâu dài tại http://jira.mongodb.org/browse/SERVER-1243 trong đó trên thực tế có một số thách thức đối với một cú pháp rõ ràng hỗ trợ "tất cả các trường hợp" trong đó các trận đấu mảng hai tìm. Trên thực tế, đã có những phương pháp "trợ giúp" cho các giải pháp cho vấn đề này, chẳng hạn như Hoạt động hàng loạt đã được triển khai sau bài đăng gốc này.

Vẫn không thể cập nhật nhiều hơn một phần tử mảng phù hợp trong một câu lệnh cập nhật duy nhất, vì vậy ngay cả với bản cập nhật "đa", tất cả những gì bạn có thể cập nhật chỉ là một phần tử được tính toán trong mảng cho mỗi tài liệu trong một tài liệu đó tuyên bố.

Giải pháp tốt nhất có thể hiện tại là tìm và lặp tất cả các tài liệu phù hợp và xử lý các cập nhật hàng loạt ít nhất sẽ cho phép nhiều hoạt động được gửi trong một yêu cầu với một phản hồi số ít. Bạn có thể tùy ý sử dụng .aggregate()để giảm nội dung mảng được trả về trong kết quả tìm kiếm xuống chỉ còn những nội dung phù hợp với điều kiện lựa chọn cập nhật:

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();

Các .aggregate()phần sẽ làm việc khi có một định danh "độc đáo" cho mảng hoặc toàn bộ nội dung cho mỗi phần tử tạo thành một "độc đáo" yếu tố riêng của mình. Điều này là do toán tử "set" $setDifferenceđược sử dụng để lọc bất kỳ falsegiá trị nào được trả về từ $mapthao tác được sử dụng để xử lý mảng cho khớp.

Nếu nội dung mảng của bạn không có các yếu tố duy nhất, bạn có thể thử một cách tiếp cận thay thế với $redact:

db.collection.aggregate([
    { "$match": { "events.handled": 1 } },
    { "$redact": {
        "$cond": {
            "if": {
                "$eq": [ { "$ifNull": [ "$handled", 1 ] }, 1 ]
            },
            "then": "$$DESCEND",
            "else": "$$PRUNE"
        }
    }}
])

Trường hợp hạn chế là nếu "xử lý" trên thực tế là một trường có nghĩa là có mặt ở các cấp độ tài liệu khác thì bạn có thể sẽ nhận được kết quả không được phát hiện, nhưng sẽ ổn khi trường đó chỉ xuất hiện ở một vị trí tài liệu và là một kết quả khớp.

Các bản phát hành trong tương lai (bài 3.1 MongoDB) khi viết sẽ có một $filterthao tác đơn giản hơn:

db.collection.aggregate([
    { "$match": { "events.handled": 1 } },
    { "$project": {
        "events": {
            "$filter": {
                "input": "$events",
                "as": "event",
                "cond": { "$eq": [ "$$event.handled", 1 ] }
            }
        }
    }}
])

Và tất cả các bản phát hành hỗ trợ .aggregate()có thể sử dụng cách tiếp cận sau $unwind, nhưng việc sử dụng toán tử đó làm cho nó trở thành cách tiếp cận kém hiệu quả nhất do mở rộng mảng trong đường ống:

db.collection.aggregate([
    { "$match": { "events.handled": 1 } },
    { "$unwind": "$events" },
    { "$match": { "events.handled": 1 } },
    { "$group": {
        "_id": "$_id",
        "events": { "$push": "$events" }
    }}        
])

Trong tất cả các trường hợp phiên bản MongoDB hỗ trợ "con trỏ" từ đầu ra tổng hợp, thì đây chỉ là vấn đề chọn cách tiếp cận và lặp lại kết quả với cùng một khối mã được hiển thị để xử lý các câu lệnh cập nhật hàng loạt. Hoạt động hàng loạt và "con trỏ" từ đầu ra tổng hợp được giới thiệu trong cùng một phiên bản (MongoDB 2.6) và do đó thường làm việc cùng nhau để xử lý.

Trong các phiên bản thậm chí trước đó, có lẽ tốt nhất là chỉ sử dụng .find()để trả về con trỏ và lọc ra việc thực hiện các câu lệnh để chỉ số lần phần tử mảng được khớp cho các .update()lần lặp:

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 }});
    });
});

Nếu bạn hoàn toàn quyết tâm thực hiện cập nhật "đa" hoặc cho rằng cuối cùng sẽ hiệu quả hơn so với xử lý nhiều cập nhật cho mỗi tài liệu phù hợp, thì bạn luôn có thể xác định số lượng tối đa của các kết quả khớp có thể và chỉ thực hiện cập nhật "nhiều" lần, cho đến khi về cơ bản không có thêm tài liệu để cập nhật.

Một cách tiếp cận hợp lệ cho các phiên bản MongoDB 2.4 và 2.2 cũng có thể được sử dụng .aggregate()để tìm giá trị này:

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 })
}

Dù thế nào đi nữa, có một số điều bạn không muốn làm trong bản cập nhật:

  1. Không "cập nhật một lần" cập nhật mảng: Nếu bạn nghĩ rằng có thể hiệu quả hơn để cập nhật toàn bộ nội dung mảng trong mã và sau đó chỉ $settoàn bộ mảng trong mỗi tài liệu. Điều này có vẻ nhanh hơn để xử lý, nhưng không có gì đảm bảo rằng nội dung mảng không thay đổi kể từ khi nó được đọc và cập nhật được thực hiện. Mặc dù $setvẫn là một toán tử nguyên tử, nó sẽ chỉ cập nhật mảng với những gì nó "nghĩ" là dữ liệu chính xác và do đó có khả năng ghi đè lên bất kỳ thay đổi nào xảy ra giữa đọc và ghi.

  2. Không tính toán các giá trị chỉ mục để cập nhật: Trường hợp tương tự như cách tiếp cận "một lần bắn", bạn chỉ cần tìm ra vị trí 0và vị trí đó 2(v.v.) là các yếu tố để cập nhật và mã hóa chúng theo và tuyên bố cuối cùng như:

    { "$set": {
        "events.0.handled": 0,
        "events.2.handled": 0
    }}

    Một lần nữa, vấn đề ở đây là "giả định" rằng các giá trị chỉ mục được tìm thấy khi tài liệu được đọc là cùng các giá trị chỉ mục trong mảng thứ tại thời điểm cập nhật. Nếu các mục mới được thêm vào mảng theo cách thay đổi thứ tự thì các vị trí đó không còn hiệu lực và thực tế các mục sai được cập nhật.

Vì vậy, cho đến khi có một cú pháp hợp lý được xác định để cho phép xử lý nhiều phần tử mảng phù hợp trong câu lệnh cập nhật duy nhất thì cách tiếp cận cơ bản là cập nhật từng phần tử mảng phù hợp trong một câu lệnh ngẫu nhiên (lý tưởng là Hàng loạt) hoặc về cơ bản xử lý các phần tử mảng tối đa để cập nhật hoặc tiếp tục cập nhật cho đến khi không có kết quả sửa đổi nào được trả về. Ở bất kỳ giá nào, bạn nên "luôn luôn" xử lý các$ cập nhật vị trí trên phần tử mảng phù hợp, ngay cả khi đó chỉ cập nhật một phần tử cho mỗi câu lệnh.

Các hoạt động hàng loạt trên thực tế là giải pháp "tổng quát" để xử lý bất kỳ hoạt động nào hoạt động thành "nhiều hoạt động" và vì có nhiều ứng dụng cho việc này hơn là chỉ cập nhật các phần tử mảng đa biến có cùng giá trị, nên dĩ nhiên nó đã được thực hiện và đây là cách tiếp cận tốt nhất để giải quyết vấn đề này.


8

Tôi ngạc nhiên điều này vẫn chưa được giải quyết trong mongo. Nhìn chung, mongo dường như không tuyệt vời khi xử lý các mảng con. Bạn không thể đếm mảng phụ đơn giản chẳng hạn.

Tôi đã sử dụng giải pháp đầu tiên của Javier. Đọc mảng thành các sự kiện sau đó lặp qua và xây dựng tập 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});

Điều này có thể được trừu tượng hóa thành một hàm bằng cách sử dụng một cuộc gọi lại cho bài kiểm tra có điều kiện


Cảm ơn vì điều đó! Không thể tin rằng tính năng này vẫn không được hỗ trợ! Đã sử dụng điều này để tăng mọi mục của một phân đoạn, cho người khác đọc ... để cập nhật mọi mục chỉ cần xóa câu lệnh if.
Zaheer

9
Đây không phải là một giải pháp an toàn. Nếu một bản ghi được thêm vào trong khi bạn đang chạy bản cập nhật, bạn sẽ làm hỏng dữ liệu của mình.
Merc

4

Tôi đã tìm kiếm một giải pháp cho vấn đề này bằng trình điều khiển mới nhất cho C # 3.6 và đây là cách khắc phục cuối cùng tôi đã giải quyết. Chìa khóa ở đây là sử dụng "$ []" mà theo MongoDB là mới kể từ phiên bản 3.6. Xem https://docs.mongodb.com/manual/reference/operator/update/poseitable-all/#up. S [] để biết thêm thông tin.

Đây là mã:

{
   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});
}

Để biết thêm ngữ cảnh, hãy xem bài viết gốc của tôi ở đây: Xóa phần tử mảng khỏi TẤT CẢ các tài liệu bằng trình điều khiển MongoDB C #


4

Các chủ đề rất cũ, nhưng tôi đã tìm kiếm câu trả lời ở đây do đó cung cấp giải pháp mới.

Với MongoDB phiên bản 3.6+, giờ đây có thể sử dụng toán tử vị trí để cập nhật tất cả các mục trong một mảng. Xem tài liệu chính thức tại đây .

Truy vấn sau đây sẽ làm việc cho câu hỏi được hỏi ở đây. Tôi cũng đã xác minh với trình điều khiển Java-MongoDB và nó hoạt động thành công.

.update(   // or updateMany directly, removing the flag for 'multi'
   {"events.profile":10},
   {$set:{"events.$[].handled":0}},  // notice the empty brackets after '$' opearor
   false,
   true
)

Hy vọng điều này sẽ giúp một người như tôi.


1

Tôi đã thử sau đây và nó hoạt động tốt.

.update({'events.profile': 10}, { '$set': {'events.$.handled': 0 }},{ safe: true, multi:true }, callback function);

// hàm gọi lại trong trường hợp nodejs


Mã này chỉ cập nhật mục phù hợp đầu tiên trong mảng. Câu trả lời sai.
Hamlett

Nó hoạt động cho v2.6. Bạn có thể ở một phiên bản cũ hơn? Đây là doc docs.mongodb.com/manual/reference/method/db.collection.update/ triệt
Jialin Zou

1

Bạn có thể cập nhật tất cả các yếu tố trong MongoDB

db.collectioname.updateOne(
{ "key": /vikas/i },
{ $set: { 
 "arr.$[].status" : "completed"
} }
)

Nó sẽ cập nhật tất cả giá trị "trạng thái" thành "đã hoàn thành" trong mảng "mảng"

Nếu chỉ có một tài liệu

db.collectioname.updateOne(
 { key:"someunique", "arr.key": "myuniq" },
 { $set: { 
   "arr.$.status" : "completed", 
   "arr.$.msgs":  {
                "result" : ""
        }
   
 } }
)

Nhưng nếu không phải một và bạn cũng không muốn tất cả các tài liệu trong mảng cập nhật thì bạn cần phải lặp qua phần tử và bên trong khối if

db.collectioname.find({findCriteria })
  .forEach(function (doc) {
    doc.arr.forEach(function (singlearr) {
      if (singlearr check) {
        singlearr.handled =0
      }
    });
    db.collection.save(doc);
  });

0

Trên thực tế, lệnh save chỉ là ví dụ của lớp Document. Điều đó có rất nhiều phương thức và thuộc tính. Vì vậy, bạn có thể sử dụng hàm lean () để giảm tải công việc. Tham khảo tại đây. https://hashnode.com/post/why-are-mongoose-mongodb-odm-lean-queries-faster-than-n normal-query -cillvawhq0062kj53asxoyn7j

Một vấn đề khác với chức năng lưu, điều đó sẽ khiến dữ liệu xung đột với đa lưu cùng một lúc. Model.Update sẽ làm cho dữ liệu nhất quán. Vì vậy, để cập nhật nhiều mục trong mảng tài liệu. Sử dụng ngôn ngữ lập trình quen thuộc của bạn và thử một cái gì đó như thế này, tôi sử dụng cầy mangut trong đó:

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))
})

0

Toán tử $ [] chọn tất cả các mảng lồng nhau .. Bạn có thể cập nhật tất cả các mục mảng với '$ []'

.update({"events.profile":10},{$set:{"events.$[].handled":0}},false,true)

Tài liệu tham khảo


Bạn có thể giải thích lý do tại sao bạn bao gồm "sai, đúng" ở cuối không? Tôi không thể tìm thấy nó trong tài liệu.
garson

Trả lời sai tất cả các toán tử vị trí $[] chỉ cập nhật tất cả các trường trong mảng đã chỉ định. Những gì hoạt động là toán tử vị trí được lọc $[identifier]mà toán tử trên các trường mảng phù hợp với các điều kiện được chỉ định. Nên được sử dụng với Chuyển động arrayFilters : docs.mongodb.com/manual/release-notes/3.6/#arrayfiltersdocs.mongodb.com/manual/reference/operator/update/ trộm
Lawrence Eagles

0

Xin lưu ý rằng một số câu trả lời trong chủ đề này gợi ý sử dụng $ [] là SAI.

db.collection.update(
   {"events.profile":10},
   {$set:{"events.$[].handled":0}},
   {multi:true}
)

Đoạn mã trên sẽ cập nhật "xử lý" thành 0 cho tất cả các thành phần trong mảng "sự kiện", bất kể giá trị "hồ sơ" của nó. Truy vấn {"events.profile":10}chỉ để lọc toàn bộ tài liệu, không phải tài liệu trong mảng. Trong trường hợp này nó là điều bắt buộc để sử dụng $[elem]với arrayFilterschỉ định điều kiện của mục mảng để trả lời Neil Lunn là đúng.


0

Cập nhật trường mảng trong nhiều tài liệu trong mongo db.

Sử dụng $ pull hoặc $ push với cập nhật nhiều truy vấn để cập nhật các phần tử mảng trong mongoDb.

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."
            });
        }
    });

0

Đầu tiên: mã của bạn không hoạt động vì bạn đang sử dụng toán tử vị trí $ chỉ xác định một phần tử để cập nhật trong một mảng nhưng thậm chí không chỉ định rõ ràng vị trí của nó trong mảng.

Những gì bạn cần là toán tử vị trí được lọc $[<identifier>]. Nó sẽ cập nhật tất cả các yếu tố phù hợp với điều kiện lọc mảng.

Giải pháp:

db.collection.update({"events.profile":10}, { $set: { "events.$[elem].handled" : 0 } },
   {
     multi: true,
     arrayFilters: [ { "elem.profile": 10 } ]
})

Truy cập tài liệu mongodb tại đây

Những gì mã làm:

  1. {"events.profile":10} lọc bộ sưu tập của bạn và trả lại các tài liệu phù hợp với bộ lọc

  2. Các $setnhà điều hành cập nhật: Sửa phù hợp với lĩnh vực văn bản nó hoạt động trên.

  3. {multi:true}Nó làm cho .update()sửa đổi tất cả các tài liệu phù hợp với bộ lọc do đó hoạt động nhưupdateMany()

  4. { "events.$[elem].handled" : 0 } and arrayFilters: [ { "elem.profile": 10 } ] Kỹ thuật này liên quan đến việc sử dụng mảng vị trí được lọc với ArrayFilters. mảng vị trí được lọc ở đây $[elem]hoạt động như một trình giữ chỗ cho tất cả các phần tử trong các trường mảng phù hợp với các điều kiện được chỉ định trong bộ lọc mảng.

Bộ lọc mảng

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.