Không thể truy vấn cấu trúc này để có kết quả bạn muốn nếu không biết tất cả các forms
có thể có tên trước và sử dụng chúng trong truy vấn. Nó sẽ rất lộn xộn ở bất kỳ mức độ nào. Điều đó nói rằng, hãy đọc khi tôi giải thích cách nó có thể được thực hiện.
Có một vấn đề với cấu trúc của những tài liệu này sẽ ngăn cản bạn thực hiện bất kỳ phân tích truy vấn hợp lý nào. Như vậy, bạn sẽ phải biết tất cả các trường tên biểu mẫu có thể có để lọc ra bất kỳ thứ gì.
Cấu trúc hiện tại của bạn có các biểu mẫu chứa một tài liệu con, trong đó mỗi khóa chứa một tài liệu con khác với một thuộc tính duy nhất, status
. Điều này khó duyệt qua dưới dạng forms
của bạn phần tử có cấu trúc tùy ý cho mỗi tài liệu bạn tạo. Điều đó có nghĩa là mẫu sẽ giảm dần sang trạng thái status
thông tin bạn muốn so sánh các thay đổi cho mọi tài liệu trong bộ sưu tập của mình.
Đây là những gì tôi muốn nói về con đường. Để đạt được trạng thái trong bất kỳ phần tử nào, bạn phải làm như sau
Với yếu tố thứ hai luôn thay đổi. Không có cách nào thành ký tự đại diện một cái gì đó như thế này vì cách đặt tên được coi là rõ ràng.
Đây có thể được coi là một cách dễ dàng để thực hiện tuần tự hóa dữ liệu từ các biểu mẫu của bạn nhưng tôi thấy linh hoạt hơn thay thế. Những gì bạn cần là một cấu trúc tài liệu mà bạn có thể duyệt theo một mẫu chuẩn. Đây luôn là điều đáng được quan tâm trong thiết kế. Thực hiện như sau:
{
"_id" : "Tvq444454j",
"name": "Jim",
"forms": [
{
"name": "Jorney",
"status":"closed"
},
{
"name": "Women",
"status":"void"
},
{
"name": "Child",
"status":"closed"
},
{
"name": "Farm",
"status":"closed"
}
]
}
Vì vậy, cấu trúc của tài liệu được thay đổi để tạo ra các forms
phần tử một Mảng và thay vì đặt trường trạng thái dưới một khóa đặt tên cho "trường biểu mẫu", chúng tôi có mỗi thành viên của Mảng như một tài liệu con chứa "trường biểu mẫu" name
và status
. Vì vậy, cả số nhận dạng và trạng thái vẫn được ghép nối với nhau nhưng bây giờ chỉ được biểu diễn dưới dạng tài liệu con. Điều quan trọng nhất này thay đổi đường dẫn truy cập đến các khóa này, như bây giờ cho cả hai tên trường và trạng thái của nó mà chúng tôi có thể thực hiện
Cái gì này có nghĩa là bạn có thể truy vấn để tìm tên của tất cả các trường trong forms
hoặc tất cả status
các trường trong forms
hoặc thậm chí tất cả các tài liệu có một name
nhất định trường và status
nhất định . Đó là nhiều tốt hơn những gì có thể được thực hiện với cấu trúc ban đầu.
Bây giờ trong trường hợp cụ thể của bạn, bạn muốn nhận được chỉ các tài liệu trong đó tất cả các trường không phải là void
. Bây giờ không có cách nào trong một truy vấn duy nhất để thực hiện điều này vì không có toán tử nào để so sánh tất cả các phần tử trong một mảng theo cách này và xem chúng có giống nhau hay không. Nhưng có hai cách tiếp cận bạn có thể thực hiện:
Cách đầu tiên và có lẽ không hiệu quả là truy vấn tất cả tài liệu có chứa một phần tử trong forms
có trạng thái status
của "void". Với Id tài liệu kết quả, bạn có thể đưa ra một truy vấn khác trả về các tài liệu không có Id đã được chỉ định.
db.forms.find({ "forms.status": "void" },{ _id: 1})
db.forms.find({ _id: $not: { $in: [<Object1>,<Object2>,<Object3>,... ] } })
Với kích thước kết quả, điều này có thể không thực hiện được và nói chung không phải là ý kiến hay vì toán tử loại trừ $not
về cơ bản là buộc quét toàn bộ của bộ sưu tập, vì vậy bạn không thể sử dụng chỉ mục.
Một cách tiếp cận khác là sử dụng đường dẫn tổng hợp như sau:
db.forms.aggregate([
{ "$unwind": "$forms" },
{ "$group": { "_id": "$_id", "status": { "$addToSet": "$forms.status" }}},
{ "$unwind": "$status" },
{ "$sort": { "_id": 1, "status": -1 }},
{ "$group": { "_id": "$_id", "status": { "$first": "$status"}}},
{ "$match":{ "status": "closed" }}
])
Tất nhiên điều đó sẽ chỉ trả về _id cho các tài liệu khớp, nhưng bạn có thể đưa ra truy vấn với $ in và trả lại toàn bộ tài liệu khớp. Điều này tốt hơn toán tử loại trừ được sử dụng trước đây và bây giờ chúng tôi có thể sử dụng một chỉ mục để tránh quét toàn bộ bộ sưu tập.
Là cách tiếp cận cuối cùng và tốt nhất xem xét hiệu suất, bạn có thể thay đổi lại tài liệu để ở cấp cao nhất, bạn giữ "trạng thái" xem bất kỳ trường nào trong biểu mẫu ở trạng thái "vô hiệu" hoặc "đã đóng". Vì vậy, ở cấp cao nhất, giá trị sẽ chỉ bị đóng nếu tất cả các mục là "đóng" và "vô hiệu" nếu có thứ gì đó không có giá trị, v.v.
Điều cuối cùng đó có nghĩa là một thay đổi có lập trình tiếp theo và tất cả các thay đổi đối với forms
các mục cũng cần cập nhật trường này để duy trì "trạng thái". Tuy nhiên, đây là cách hiệu quả nhất để tìm các tài liệu bạn cần và có thể đáng xem xét.
CHỈNH SỬA :
Ngoài việc thay đổi tài liệu để có trạng thái chính, biểu mẫu truy vấn nhanh nhất trên cấu trúc đã sửa đổi thực sự là:
db.forms.find({ "forms": { "$not": { "$elemMatch": { "status": "void" } } } })