Lỗi là do nó không còn là một mảng sau khi bạn $ unwind
và do đó không còn là đối số hợp lệ cho $ size
.
Có vẻ như bạn đang cố gắng "hợp nhất" một vài câu trả lời hiện có mà không hiểu chúng đang làm gì. Điều bạn thực sự muốn ở đây là $ filter
và $ size
db.collection.aggregate([
{ "$project": {
"total": {
"$size": {
"$filter": {
"input": "$Array",
"cond": { "$eq": [ "$$this.field1", "a" ] }
}
}
}
}}
])
Hoặc "phát minh lại bánh xe" bằng cách sử dụng $ Reduce
:
db.collection.aggregate([
{ "$project": {
"total": {
"$reduce": {
"input": "$Array",
"initialValue": 0,
"in": {
"$sum": [
"$$value",
{ "$cond": [{ "$eq": [ "$$this.field1", "a" ] }, 1, 0] }
}
}
}
}}
])
Hoặc cho những gì bạn đang cố gắng thực hiện với $ unwind
, bạn thực sự $ group
một lần nữa để "đếm" có bao nhiêu trận đấu:
db.collection.aggregate([
{ "$unwind": "$Array" },
{ "$match": { "Array.field1": "a" } },
{ "$group": {
"_id": "$_id",
"total": { "$sum": 1 }
}}
])
Hai hình thức đầu tiên là "tối ưu" cho môi trường MongoDB hiện đại. Biểu mẫu cuối cùng với $ unwind
và $ group
là một cấu trúc "kế thừa" thực sự không cần thiết cho loại hoạt động này kể từ MongoDB 2.6, mặc dù với một số toán tử hơi khác.
Trong hai đầu tiên đó, về cơ bản, chúng ta đang so sánh field1
giá trị của mỗi phần tử mảng trong khi nó vẫn là một mảng. Cả $ filter
và $ giảm
là các toán tử hiện đại được thiết kế để làm việc với một mảng hiện có tại chỗ. Việc so sánh tương tự được thực hiện trên từng cái bằng cách sử dụng tổng hợp $ eq
toán tử trả về giá trị boolean dựa trên việc các đối số được đưa ra có "bằng" hay không. Trong trường hợp này, trên mỗi thành viên mảng giá trị mong đợi là "a"
.
Trong trường hợp của $ filter
, mảng thực sự vẫn nguyên vẹn ngoại trừ bất kỳ phần tử nào không đáp ứng điều kiện được cung cấp trong "cond"
bị xóa khỏi mảng. Vì chúng ta vẫn có "mảng" làm đầu ra, nên sau đó, chúng ta có thể sử dụng $ size
toán tử để đo số phần tử mảng còn lại sau khi điều kiện lọc đó được xử lý.
$ giảm
mặt khác, hoạt động thông qua các phần tử của mảng và cung cấp một biểu thức cho mỗi phần tử và một giá trị "bộ tích lũy" được lưu trữ, mà chúng tôi đã khởi tạo bằng "initialValue"
. Trong trường hợp này, cùng một $ eq
kiểm tra được áp dụng trong $ cond
nhà điều hành. Đây là "bậc ba" hoặc if / then / else
toán tử điều kiện cho phép một biểu thức được kiểm tra trả về giá trị boolean để trả về then
giá trị khi true
hoặc else
giá trị khi false
.
Trong biểu thức đó, chúng ta trả về 1
hoặc 0
tương ứng và cung cấp kết quả tổng thể của việc thêm giá trị trả về đó và "bộ tích lũy" "$$ value"
hiện tại với $ sum
toán tử để thêm chúng lại với nhau.
Biểu mẫu cuối cùng được sử dụng $ unwind
trên mảng. Điều này thực sự làm là giải cấu trúc các thành viên mảng để tạo một "tài liệu mới" cho mọi thành viên mảng và các trường cha liên quan của nó trong tài liệu gốc. Điều này "sao chép" tài liệu chính một cách hiệu quả cho mọi thành viên mảng.
Sau khi bạn $ unwind
cấu trúc của các tài liệu được thay đổi sang dạng "phẳng hơn". Đây là lý do tại sao bạn có thể thực hiện $ so khớp tiếp theo
giai đoạn đường ống để loại bỏ các tài liệu không khớp.
Điều này đưa chúng tôi đến $ group
được áp dụng để "tập hợp lại" tất cả thông tin liên quan đến một khóa chung. Trong trường hợp này, đó là _id
trường của tài liệu gốc, tất nhiên đã được sao chép vào mọi tài liệu được tạo bởi $ unwind
. Khi quay lại "khóa chung" này dưới dạng một tài liệu, chúng tôi có thể "đếm" các "tài liệu" còn lại được trích xuất từ mảng bằng cách sử dụng $ sum
bộ tích lũy.
Nếu chúng tôi muốn lấy lại "mảng" còn lại, thì bạn có thể $ push
và xây dựng lại mảng chỉ với các thành viên còn lại:
{ "$group": {
"_id": "$_id",
"Array": { "$push": "$Array" },
"total": { "$sum": 1 }
}}
Nhưng tất nhiên thay vì sử dụng $ size
trong một giai đoạn quy trình khác, chúng ta vẫn có thể "đếm" đơn giản như chúng ta đã làm với $ sum