2013-04-27 42 views
9

Tôi gặp tài liệu sau đây trong MongoDBphù hợp với lĩnh vực nội bộ trong MongoDB

{ 
     "_id" : ObjectId("517b88decd483543a8bdd95b"), 
     "studentId" : 23, 
     "students" : [ 
      { 
      "id" : 23, 
      "class" : "a" 
      }, 
      { 
      "id" : 55, 
      "class" : "b" 
      } 
     ] 
    } 
    { 
     "_id" : ObjectId("517b9d05254e385a07fc4e71"), 
     "studentId" : 55, 
     "students" : [ 
      { 
      "id" : 33, 
      "class" : "c" 
      } 
     ] 
    } 

Note: Không phải là dữ liệu thực tế nhưng schema là chính xác như vậy.

Requirement: Tìm tài liệu mà phù hợp với studentIdstudents.id (id bên trong mảng học sinh sử dụng đơn truy vấn.

Tôi đã thử đoạn code như dưới đây

db.data.aggregate({$match:{"students.id":"$studentId"}},{$group:{_id:"$student"}}); 

Result: rỗng Array, Nếu tôi thay thế {"students.id": "$ studentId"} thành {"students.id": 33} nó sẽ trả lại tài liệu thứ hai trong json được hiển thị ở trên.

Có thể lấy tài liệu cho kịch bản này bằng truy vấn đơn không?

Trả lời

13

Nếu có thể, tôi khuyên bạn nên đặt điều kiện trong khi lưu trữ dữ liệu để bạn có thể kiểm tra thật nhanh (isInStudentsList). Sẽ rất nhanh khi thực hiện loại truy vấn đó.

Nếu không, có một cách tương đối phức tạp của việc sử dụng các đường ống khuôn khổ tập hợp để làm những gì bạn muốn trong một truy vấn duy nhất:

db.students.aggregate( 
    {$project: 
     {studentId: 1, studentIdComp: "$students.id"}}, 
    {$unwind: "$studentIdComp"}, 
    {$project : { studentId : 1, 
     isStudentEqual: { $eq : [ "$studentId", "$studentIdComp" ] }}}, 
    {$match: {isStudentEqual: true}}) 

Với ví dụ đầu vào của bạn đầu ra sẽ là:

{ 
    "result" : [ 
     { 
      "_id" : ObjectId("517b88decd483543a8bdd95b"), 
      "studentId" : 23, 
      "isStudentEqual" : true 
     } 
    ], 
    "ok" : 1 
} 

Giải thích ngắn gọn về các bước:

  1. Tạo bản chiếu tài liệu chỉ với studentId và trường mới có mảng chứa chỉ id (do đó tài liệu đầu tiên chứa [23, 55].
  2. Sử dụng cấu trúc đó, $unwind. Điều đó tạo ra một tài liệu tạm thời mới cho mỗi phần tử mảng trong mảng studentIdComp.
  3. Bây giờ, lấy các tài liệu đó và tạo một bản chiếu tài liệu mới, tiếp tục có studentId và thêm trường mới có tên isStudentEqual so sánh sự bình đẳng của hai trường, studentIdstudentIdComp. Hãy nhớ rằng tại thời điểm này có một tài liệu tạm thời chứa hai trường đó.
  4. Cuối cùng, hãy kiểm tra xem giá trị so sánh isStudentEqual có đúng không và trả lại các tài liệu đó (chứa tài liệu gốc _idstudentId.
  5. Nếu học sinh nằm trong danh sách nhiều lần, bạn có thể cần nhóm các kết quả theo số studentId hoặc _id để ngăn trùng lặp (nhưng tôi không biết rằng bạn cần điều đó).
+0

Làm việc tốt, Cảm ơn bạn đã giải thích. +1 – karthick

-1

db.data.find({students: {$elemMatch: {id: 23}} , studentId: 23});

+0

Tôi tin rằng câu hỏi là làm thế nào để tìm thấy tất cả các tài liệu mà điều kiện là đúng (chọn tài liệu mà danh sách sinh viên chứa StudentID.) – WiredPrairie

0

Đáng tiếc là nó không thể; (

để giải quyết vấn đề này, nó là cần thiết để sử dụng một $ nơi tuyên bố (ví dụ: Finding embeded document in mongodb?),

nhưng $ nơibị hạn chế sử dụng với khung tổng hợp

+0

@Asya nhờ;) –

+0

lưu ý rằng $ mà không phải là cần thiết với Aggregation khuôn khổ mặc dù (như Câu trả lời của WiredPrairie cho thấy bạn có thể sử dụng $ project để tạo trường mới và sau đó sử dụng $ match) –

+0

chính xác @AsyaKamsky, nhưng trong nhiều câu hỏi, tôi quan sát tình huống cổ điển: so sánh một trường và một trường khác trong một số phân cấp. tôi biết, vấn đề đó nói chung trong một mô hình dữ liệu xấu. nhiều devs tạo mô hình lưu trữ dữ liệu chỉ cần sao chép trực tiếp + dán từ các kho quan hệ;) –