2015-09-23 19 views
5

Tôi đã 2 DynamicDocuments:Mongo Embedded Document Query

class Tasks(db.DynamicDocument): 
    task_id = db.UUIDField(primary_key=True,default=uuid.uuid4) 
    name = db.StringField() 
    flag = db.IntField() 

class UserTasks(db.DynamicDocument): 
    user_id = db.ReferenceField('User') 
    tasks = db.ListField(db.ReferenceField('Tasks'),default=list) 

Tôi muốn lọc các tài liệu UserTasks bằng cách kiểm tra xem giá trị flag (từ Document Nhiệm vụ) của task_id cho là 0 hoặc 1, do task_id và user_id. Vì vậy, tôi truy vấn theo cách sau: -

obj = UserTasks.objects.get(user_id=user_id,tasks=task_id) 

này fetches tôi một đối tượng UserTask.

Bây giờ tôi vòng quanh danh sách nhiệm vụ và trước tiên tôi nhận nhiệm vụ tương đương và sau đó kiểm tra giá trị cờ của nó theo cách sau.

task_list = obj.tasks 
for t in task_list: 
    if t['task_id'] == task_id: 
     print t['flag'] 

Có/cách trực tiếp hơn về truy vấn UserTasks Document để lấy giá trị cờ của tài liệu Tasks.

PS: Tôi có thể lấy trực tiếp giá trị cờ từ Tài liệu Tasks, nhưng tôi cũng cần kiểm tra xem tác vụ có được liên kết với người dùng hay không. Do đó tôi đã trực tiếp truy vấn tài liệu USerTasks.

+0

Phiên bản mongoengine và pymongo bạn đang sử dụng? –

+0

'pymongo == 3.0.3' và' mongoengine == 0.10.0' – PythonEnthusiast

Trả lời

2

Chúng tôi có thể trực tiếp lọc trên tài liệu có các trường ReferenceField's trong một truy vấn không?

Không, của nó không thể trực tiếp lọc một tài liệu với các lĩnh vực ReferenceField như làm điều này sẽ đòi hỏi tham gia và MongoDB không hỗ trợ tham gia.

Theo tài liệu MongoDB trên database references:

MongoDB không hỗ trợ tham gia. Trong MongoDB, một số dữ liệu không được chuẩn hóa, hoặc được lưu trữ với dữ liệu liên quan trong tài liệu để loại bỏ nhu cầu tham gia.

Từ page khác trên trang web chính thức:

Nếu chúng ta đang sử dụng một cơ sở dữ liệu quan hệ, chúng ta có thể thực hiện liên kết người sử dụng và các cửa hàng, và nhận được tất cả đối tượng của chúng tôi trong một truy vấn duy nhất. Nhưng MongoDB không hỗ trợ kết nối và đôi khi, yêu cầu bit không chuẩn hóa.

Người theo chủ nghĩa thuần túy quan hệ có thể cảm thấy không thoải mái, như thể chúng tôi là vi phạm một số luật phổ quát. Nhưng hãy nhớ rằng các bộ sưu tập MongoDB không tương đương với các bảng quan hệ; mỗi mục tiêu một mục tiêu thiết kế độc đáo là . Bảng được chuẩn hóa cung cấp một đoạn dữ liệu riêng lẻ, . Tuy nhiên, một tài liệu, đại diện chặt chẽ hơn đối với một đối tượng nói chung là .

Vì vậy, trong 1 truy vấn, chúng tôi không thể đồng thời lọc tasks với một giá trị cờ nói riêng và với trao user_idtask_id trên mô hình UserTasks.

Làm cách nào để thực hiện lọc?

Để thực hiện lọc theo các điều kiện bắt buộc, , chúng tôi sẽ cần thực hiện 2 truy vấn.

Trong truy vấn đầu tiên, chúng tôi sẽ cố gắng để lọc các mô hình Tasks với trao task_idflag. Sau đó, trong truy vấn thứ 2, chúng tôi sẽ lọc mô hình UserTasks với số user_idtask đã nhận được từ truy vấn đầu tiên.

Ví dụ:

phép nói rằng chúng tôi có một user_id, task_id và chúng ta cần phải kiểm tra xem các nhiệm vụ liên quan có giá trị flag như 0.

1 Query

Đầu tiên chúng ta sẽ truy xuất các my_task với trao task_idflag như 0.

my_task = Tasks.objects.get(task_id=task_id, flag=0) # 1st query 

2 Query

Sau đó, trong truy vấn thứ 2, bạn cần phải lọc trên UserTask mô hình với trao user_idmy_task đối tượng.

my_user_task = UserTasks.objects.get(user_id=user_id, tasks=my_task) # 2nd query 

Bạn nên thực hiện truy vấn thứ 2 chỉ nếu bạn nhận được một đối tượng my_task với trao task_idflag giá trị. Ngoài ra, bạn sẽ cần phải thêm xử lý lỗi trong trường hợp không có đối tượng phù hợp.

Nếu chúng ta đã sử dụng EmbeddedDocument cho kiểu Tasks thì sao?

phép nói rằng chúng tôi đã xác định tài liệu Tasks của chúng tôi như một EmbeddedDocumenttasks trường trong UserTasks mô hình như một EmbeddedDocumentField, sau đó làm việc lọc mong muốn chúng ta có thể làm một cái gì đó như dưới đây:

my_user_task = UserTasks.objects.get(user_id=user_id, tasks__task_id=task_id, tasks__flag=0) 

Bắt cụ thể my_task từ danh sách nhiệm vụ

Truy vấn trên sẽ trả về tài liệu UserTask ntain tất cả các tasks. Sau đó, chúng tôi sẽ cần thực hiện một số loại lặp lại để có được nhiệm vụ mong muốn.

Để thực hiện điều đó, chúng tôi có thể thực hiện việc hiểu danh sách bằng cách sử dụng enumerate(). Sau đó chỉ mục mong muốn sẽ là phần tử thứ nhất của danh sách 1 phần tử được trả về.

my_task_index = [i for i,v in enumerate(my_user_task.tasks) if v.flag==0][0] 
+0

Cảm ơn @Rahul vì đã giải thích. Tôi đã thực sự tìm ra câu trả lời như vậy. Chỉ một câu hỏi nữa thôi. Tôi có thể thực hiện lọc trong một truy vấn nếu Mô hình Tác vụ 'là một Tài liệu được nhúng không? Nếu có, thì làm thế nào? – PythonEnthusiast

+0

Chúng ta có thể thực hiện lọc trong một truy vấn duy nhất nhưng nó sẽ trả về toàn bộ tài liệu 'UserTasks' chứa tất cả các' nhiệm vụ'. Bạn sẽ phải thực hiện một số lần lặp lại để thực hiện tác vụ mong muốn. –

0

@Praful, dựa trên giản đồ của bạn, bạn cần hai truy vấn vì MongoDB không có tham gia, vì vậy nếu bạn muốn nhận được "tất cả các dữ liệu" trong một truy vấn bạn cần một sơ đồ mà phù hợp với trường hợp đó. ReferenceField là một trường đặc biệt làm tải trọng chậm của bộ sưu tập khác (yêu cầu truy vấn).

Dựa trên truy vấn bạn cần, tôi khuyên bạn nên thay đổi giản đồ của mình để phù hợp với điều đó. Ý tưởng đằng sau động cơ NOSQL là "không chuẩn hóa" vì vậy nó không phải là xấu để có một danh sách các EmbeddedDocument. EmbeddedDocument có thể là một tài liệu nhỏ hơn (phiên bản không chuẩn hóa) với một tập hợp các trường thay vì tất cả chúng.

Nếu bạn không muốn tải toàn bộ tài liệu vào bộ nhớ trong khi truy vấn, bạn có thể loại trừ các trường đó bằng cách sử dụng "phép chiếu". Supossing UserTasks của bạn có một danh sách các EmbeddedDocument với nhiệm vụ bạn có thể làm:

UserTasks.objects.exclude('tasks').filter(**filters) 

Tôi hy vọng nó sẽ giúp bạn.

Chúc may mắn!

+0

Nếu, ở tất cả, tôi làm cho mô hình 'Tasks' là' EmbeddedDocument' và 'UserTasks' có danh sách các tác vụ EmbeddedDocument, sau đó làm thế nào tôi có được chi tiết của một nhiệm vụ cụ thể? tức là ví dụ: - Nếu tôi có danh sách các tác vụ được nhúng và tôi muốn tìm một tác vụ có 'id = 1', tôi sẽ truy vấn bằng' UserTasks.objects (tasks__task_id = 1) '. Nó vẫn sẽ trả về cho tôi một đối tượng 'UserTask', trong đó tôi vẫn phải vòng quanh danh sách các nhiệm vụ mà tôi đã làm trước đó. Làm thế nào là nó khác nhau hoặc tôi đang suy nghĩ theo một hướng sai? – PythonEnthusiast

+0

Bạn có thể cho tôi một ví dụ có thể giải quyết mục đích của tôi trong 1 truy vấn bằng tài liệu được nhúng không? Hoặc ngay cả khi tôi đã thay đổi giản đồ, cái nào là phù hợp trong trường hợp này? Vui lòng cung cấp một ví dụ. Cảm ơn :) – PythonEnthusiast

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