2015-06-17 22 views
5

Tôi có bộ sưu tập mongodb. Khi tôi làm.Cách xóa các giá trị trùng lặp bên trong danh sách trong mongodb

db.bill.find({}) 

tôi nhận được,

{ 
    "_id" : ObjectId("55695ea145e8a960bef8b87a"), 
    "name" : "ABC. Net", 
    "code" : "1-98tfv", 
    "abbreviation" : "ABC", 
    "bill_codes" : [ 190215, 44124, 190215, 147708 ], 
    "customer_name" : "abc" 
} 

tôi cần phẫu thuật để loại bỏ các giá trị nhân bản từ bill_codes. Cuối cùng, nó phải là

{ 
    "_id" : ObjectId("55695ea145e8a960bef8b87a"), 
    "name" : "ABC. Net", 
    "code" : "1-98tfv", 
    "abbreviation" : "ABC", 
    "bill_codes" : [ 190215, 44124, 147708 ], 
    "customer_name" : "abc" 
} 

Cách đạt được điều này trong mongodb.

Trả lời

15

Vâng của bạn có thể làm điều này bằng cách sử dụng khuôn khổ hợp như sau:

collection.aggregate([ 
    { "$project": { 
     "name": 1, 
     "code": 1, 
     "abbreviation": 1, 
     "bill_codes": { "$setUnion": [ "$bill_codes", [] ] } 
    }} 
]) 

Nhà điều hành $setUnion là một "thiết lập" nhà điều hành, do đó để thực hiện một "thiết lập" thì chỉ có các mặt hàng "độc đáo" là giữ phía sau.

Nếu bạn vẫn đang sử dụng một phiên bản MongoDB lớn hơn 2,6 thì bạn sẽ phải thực hiện hành động này với $unwind$addToSet thay vì:

collection.aggregate([ 
    { "$unwind": "$bill_codes" }, 
    { "$group": { 
     "_id": "$_id", 
     "name": { "$first": "$name" }, 
     "code": { "$first": "$code" }, 
     "abbreviation": { "$first": "$abbreviation" }, 
     "bill_codes": { "$addToSet": "$bill_codes" } 
    }} 
]) 

Nó không phải là hiệu quả nhưng các nhà khai thác được hỗ trợ từ phiên bản 2.2.

Tất nhiên nếu bạn thực sự muốn sửa đổi tài liệu bộ sưu tập của mình vĩnh viễn thì bạn có thể mở rộng trên tài liệu này và xử lý các cập nhật cho mỗi tài liệu cho phù hợp. Bạn có thể lấy một "con trỏ" từ .aggregate(), nhưng về cơ bản theo gương vỏ này:

db.collection.aggregate([ 
    { "$project": { 
     "bill_codes": { "$setUnion": [ "$bill_codes", [] ] }, 
     "same": { "$eq": [ 
      { "$size": "$bill_codes" }, 
      { "$size": { "$setUnion": [ "$bill_codes", [] ] } } 
     ]} 
    }}, 
    { "$match": { "same": false } } 
]).forEach(function(doc) { 
    db.collection.update(
     { "_id": doc._id }, 
     { "$set": { "bill_codes": doc.bill_codes } } 
    ) 
}) 

hơn Một chút liên quan cho các phiên bản trước đó:

db.collection.aggregate([ 
    { "$unwind": "$bill_codes" }, 
    { "$group": { 
     "_id": { 
      "_id": "$_id", 
      "bill_code": "$bill_codes" 
     }, 
     "origSize": { "$sum": 1 } 
    }}, 
    { "$group": { 
     "_id": "$_id._id", 
     "bill_codes": { "$push": "$_id.bill_code" }, 
     "origSize": { "$sum": "$origSize" }, 
     "newSize": { "$sum": 1 } 
    }}, 
    { "$project": { 
     "bill_codes": 1, 
     "same": { "$eq": [ "$origSize", "$newSize" ] } 
    }}, 
    { "$match": { "same": false } } 
]).forEach(function(doc) { 
    db.collection.update(
     { "_id": doc._id }, 
     { "$set": { "bill_codes": doc.bill_codes } } 
    ) 
}) 

Với các hoạt động được thêm vào trong đó để so sánh nếu " mảng "bị trùng lặp" giống với độ dài mảng ban đầu và chỉ trả lại các tài liệu đã bị xóa "trùng lặp" để xử lý khi cập nhật.


Có lẽ cũng nên thêm ghi chú "cho python" vào đây. Nếu bạn không quan tâm về "xác định" các tài liệu có chứa các entry mảng trùng lặp và đang chuẩn bị để "nổ" toàn bộ bộ sưu tập với bản cập nhật, sau đó chỉ cần sử dụng python .set() trong mã khách hàng để loại bỏ các bản sao:

for doc in collection.find(): 
    collection.update(
     { "_id": doc["_id"] }, 
     { "$set": { "bill_codes": list(set(doc["bill_codes"])) } } 
    ) 

Vì vậy, đó là khá đơn giản và nó phụ thuộc vào đó là cái ác lớn hơn, chi phí của việc tìm kiếm các tài liệu với bản sao hoặc cập nhật mọi tài liệu cho dù nó cần hay không.

Điều này ít nhất bao gồm các kỹ thuật.

+0

này không lưu lại bộ sưu tập. Tôi có nghĩa là làm 'db.bill.tìm lại ({}) 'lần nữa lấy giá trị trùng lặp – station

+0

@ user567797 Câu hỏi của bạn không nói rằng bạn muốn thay đổi các tài liệu được lưu trữ. Điều này đã được trả lời về "chỉ hiển thị". Bạn sẽ phải xử lý các kết quả và cập nhật từng tài liệu riêng lẻ nơi các mục thực sự được thay đổi. Đã thêm giải thích về cách thực hiện việc này và xác định tài liệu đã bị xóa khỏi mảng, do đó bạn không cần cập nhật mọi tài liệu trong bộ sưu tập. –

+0

Làm cách nào tôi có thể thực hiện việc này với truy vấn thứ hai vì tôi đang sử dụng phiên bản mongo 2.4. Cũng lưu ý rằng mã cập nhật của bạn có dấu phẩy bị thiếu. – station

1

Bạn có thể sử dụng một vòng lặp foreach với một số javascript:

db.bill.find().forEach(function(entry){ 
    var arr = entry.bill_codes; 
    var uniqueArray = arr.filter(function(elem, pos) { 
     return arr.indexOf(elem) == pos; 
    }); 
    entry.bill_codes = uniqueArray; 
    db.bill.save(entry); 
}) 
Các vấn đề liên quan