2014-12-12 21 views
6

Tôi có một "lớp" tài liệu như:Aggregation Khung MongoDB của: Dự án chỉ phù hợp với các yếu tố của một mảng

{ 
className: "AAA", 
students: [ 
    {name:"An", age:"13"}, 
    {name:"Hao", age:"13"}, 
    {name:"John", age:"14"}, 
    {name:"Hung", age:"12"} 
    ] 
} 

Và tôi muốn để có được những sinh viên có tên là "An", chỉ nhận được phù hợp với yếu tố trong mảng "sinh viên". Tôi có thể làm điều đó với chức năng find() như:

>db.class.find({"students.name":"An"}, {"students.$":true}) 
{ 
"_id" : ObjectId("548b01815a06570735b946c1"), 
"students" : [ 
    { 
     "name" : "An", 
     "age" : "13" 
    } 
]} 

Đó là tốt, nhưng khi tôi làm như vậy với tập hợp như sau, nó nhận được lỗi:

db.class.aggregate([ 
    {$match:{"students.name":'An'}}, 
    {$project:{"students.$":true}} 
]) 

Lỗi là:

uncaught exception: aggregate failed: { 
    "errmsg" : "exception: FieldPath field names may not start with '$'.", 
    "code" : 16410, 
    "ok" : 0 
} 

Tại sao? Tôi không thể sử dụng "$" cho mảng trong toán tử $ project của aggregate() trong khi có thể sử dụng mảng này trong toán tử dự án của hàm find().

Trả lời

1

Hãy thử sử dụng các nhà điều hành thư giãn trong đường ống: http://docs.mongodb.org/manual/reference/operator/aggregation/unwind/#pipe._S_unwind

hợp của bạn sẽ trông giống như

db.class.aggregate([ 
    { $match: { "students.name": "An" }, 
    { $unwind: "$students" }, 
    { $project: { "students": 1 } } 
]) 
+0

Tôi đã thử nó trước đây, nhưng tôi nghĩ rằng giải pháp này là không tốt. Khi chúng tôi sử dụng $ thư giãn, tài liệu sẽ được sao chép rất nhiều thời gian (như số phần tử trong mảng), có thể ảnh hưởng đến hiệu suất, tôi muốn dự án thay vì thư giãn nó. – Deka

+0

Điều đó có ý nghĩa. Những gì bạn có thể làm sau đó là chuyển đổi thứ tự của thư giãn và kết hợp trong các đường ống để bạn lọc các tài liệu của bạn đầu tiên và sau đó thư giãn để chiếu dễ dàng hơn. Xem câu trả lời được cập nhật. – atyagi

+0

Nó sẽ là giải pháp chấp nhận được, tôi không biết tại sao "Tôi không thể dùng" $ "cho mảng trong $ project operator của aggregate() trong khi có thể dùng cái này trong toán tử dự án find()" – Deka

3

Từ docs:

Use $ in the projection document of the find() method or the findOne() method when you only need one particular array element in selected documents.

Nhà điều hành theo vị trí $ không thể được sử dụng trong một giai đoạn dự báo đường ống tổng hợp. Nó không được nhận ra ở đó. Điều này có ý nghĩa, bởi vì, khi bạn thực hiện một phép chiếu cùng với một truy vấn tìm kiếm, đầu vào cho phần chiếu của truy vấn là một tài liệu duy nhất đã khớp với truy vấn. Ngữ cảnh của trận đấu được biết ngay cả trong khi chiếu . Vì vậy, đối với mỗi tài liệu phù hợp với truy vấn, toán tử chiếu được áp dụng sau đó và ở đó trước khi kết quả phù hợp tiếp theo được tìm thấy.

Trong trường hợp:

db.class.aggregate([ 
    {$match:{"students.name":'An'}}, 
    {$project:{"students.$":true}} 
]) 

Các aggregation đường ống là một tập hợp các giai đoạn. Mỗi giai đoạn là hoàn toàn không biết và độc lập với các giai đoạn trước đó hoặc tiếp theo của nó. Một bộ tài liệu vượt qua một giai đoạn hoàn toàn trước khi được chuyển sang giai đoạn tiếp theo trong đường ống. Giai đoạn đầu tiên trong trường hợp này là giai đoạn $match, tất cả các tài liệu được lọc dựa trên điều kiện đối sánh. Đầu vào cho giai đoạn chiếu bây giờ là đặt tài liệu đã được lọc làm một phần của giai đoạn khớp.

Vì vậy, toán tử vị trí trong giai đoạn chiếu không có ý nghĩa, vì trong giai đoạn hiện tại, nó không biết cơ sở nào đã được lọc. Do đó, các toán tử $ không được phép như là một phần của đường dẫn trường.

Tại sao công việc bên dưới hoạt động?

db.class.aggregate([ 
    { $match: { "students.name": "An" }, 
    { $unwind: "$students" }, 
    { $project: { "students": 1 } } 
]) 

Như bạn thấy, giai đoạn chiếu sẽ nhận một bộ tài liệu làm đầu vào và dự án các trường bắt buộc. Nó độc lập với các giai đoạn trước và tiếp theo của nó.

+0

Cảm ơn! Bạn đã giúp tôi hiểu tại sao "chúng ta không thể sử dụng" $ "cho mảng trong toán tử $ project của aggregate() trong khi có thể sử dụng toán tử này trong toán tử dự án của hàm find()". Tôi sẽ sử dụng giải pháp này cho dự án của mình, nhưng tôi vẫn tìm cách khác để không giải phóng mảng. Nếu có quá nhiều phần tử trong mảng, hiệu suất sẽ thấp. Dù sao ... cảm ơn bạn một lần nữa! – Deka

+1

Có, bạn là chính xác. Nếu bạn biết và chỉ mong đợi một tài liệu phụ phù hợp cho truy vấn của bạn, thì bạn nên mù quáng đi với truy vấn find() như trong câu hỏi của bạn. Nhưng thật không may, trong tập hợp, bạn chỉ đơn giản là không thể mà không cần thư giãn. – BatScream

Các vấn đề liên quan