Trong bản phát hành MongoDB hiện đại, bạn có thể. Bạn vẫn không thể "trực tiếp" áp dụng một mảng cho $concat
, tuy nhiên bạn có thể sử dụng $reduce
để làm việc với các phần tử của mảng và tạo ra cái này:
db.collection.aggregate([
{ "$addFields": {
"values": {
"$reduce": {
"input": "$values",
"initialValue": "",
"in": {
"$cond": {
"if": { "$eq": [ { "$indexOfArray": [ "$values", "$$this" ] }, 0 ] },
"then": { "$concat": [ "$$value", "$$this" ] },
"else": { "$concat": [ "$$value", "_", "$$this" ] }
}
}
}
}
}}
])
Tất nhiên là kết hợp với $indexOfArray
để không "nối" với "_"
gạch dưới khi nó là chỉ số "đầu tiên" của mảng.
Ngoài ra, "điều ước" bổ sung của tôi đã được đáp lại với $sum
:
db.collection.aggregate([
{ "$addFields": {
"total": { "$sum": "$items.value" }
}}
])
Loại này nói chung được nâng lên một chút với các toán tử tổng hợp lấy một mảng các mục. Sự khác biệt ở đây là nó có nghĩa là một "mảng" của "các tài liệu" được cung cấp trong biểu diễn được mã hóa, trái ngược với "phần tử mảng" có trong tài liệu hiện tại.
Cách duy nhất bạn thực sự có thể thực hiện kiểu nối các mục trong một mảng có trong tài liệu là thực hiện một số loại tùy chọn JavaScript, như với ví dụ này trong mapReduce:
db.collection.mapReduce(
function() {
emit( this._id, { "values": this.values.join("_") } );
},
function() {},
{ "out": { "inline": 1 } }
)
Tất nhiên nếu bạn không thực sự tổng hợp bất cứ điều gì, thì có thể cách tiếp cận tốt nhất là chỉ cần thực hiện thao tác "tham gia" đó trong mã khách hàng của bạn trong quá trình xử lý kết quả truy vấn của bạn. Nhưng nếu nó cần được sử dụng cho một số mục đích trên các tài liệu thì mapReduce sẽ là nơi duy nhất bạn có thể sử dụng nó.
Tôi có thể thêm rằng "ví dụ" Tôi rất thích một thứ như thế này hoạt động:
{
"items": [
{ "product": "A", "value": 1 },
{ "product": "B", "value": 2 },
{ "product": "C", "value": 3 }
]
}
Và tổng hợp:
db.collection.aggregate([
{ "$project": {
"total": { "$add": [
{ "$map": {
"input": "$items",
"as": "i",
"in": "$$i.value"
}}
]}
}}
])
Nhưng nó không hoạt động theo cách đó vì $add
mong đợi các đối số trái ngược với một mảng từ tài liệu. Thở dài! :(. Một phần của lý do "theo thiết kế" cho điều này có thể được lập luận rằng "chỉ vì" nó là một mảng hoặc "danh sách" các giá trị đơn lẻ được chuyển vào từ kết quả của phép biến đổi, nó không được "đảm bảo" rằng đó là các giá trị kiểu số riêng thực sự "hợp lệ" mà toán tử mong đợi. Ít nhất là không có ở các phương pháp "kiểm tra kiểu" được triển khai hiện tại.
Điều đó có nghĩa là bây giờ chúng ta vẫn phải làm điều này:
db.collection.aggregate([
{ "$unwind": "$items" },
{ "$group": {
"_id": "$_id",
"total": { "$sum": "$items.value" }
}}
])
Và thật đáng buồn là sẽ không có cách nào áp dụng toán tử nhóm như vậy để nối các chuỗi.
Vì vậy, bạn có thể hy vọng vào một số loại thay đổi về điều này hoặc hy vọng vào một số thay đổi cho phép thay đổi biến có phạm vi bên ngoài trong phạm vi của $map
hoạt động theo một cách nào đó. Tốt hơn là một $join
mới hoạt động cũng sẽ được hoan nghênh. Nhưng những điều này không tồn tại khi được viết và có lẽ sẽ không tồn tại trong một thời gian tới.