2010-11-15 44 views
11

Giả sử bạn có một số lượng lớn người dùng (M) và một số lượng lớn tài liệu (N) và bạn muốn mỗi người dùng có thể đánh dấu từng tài liệu đọc hoặc chưa đọc (giống như bất kỳ hệ thống email nào). Cách tốt nhất để đại diện cho điều này trong MongoDB là gì? Hoặc bất kỳ cơ sở dữ liệu tài liệu nào khác?MongoDB/NOSQL: Cách tiếp cận tốt nhất để xử lý trạng thái đọc/chưa đọc trên tin nhắn

Có một số câu hỏi về StackOverflow hỏi câu hỏi này cho cơ sở dữ liệu quan hệ nhưng tôi không thấy bất kỳ với các khuyến nghị cho cơ sở dữ liệu tài liệu:

What's the most efficient way to remember read/unread status across multiple items?

Implementing an efficient system of "unread comments" counters

Điển hình là các câu trả lời liên quan đến một danh sách bảng mọi thứ mà người dùng đã đọc: (ví dụ: id người dùng, id tài liệu) với một số tối ưu có thể cho ngày bị cắt cho phép đánh dấu tất cả là đã đọc để xóa cơ sở dữ liệu và bắt đầu lại biết rằng bất cứ điều gì trước ngày đó được 'đọc '.

Vì vậy, các chuyên gia MongoDB/NOSQL, bạn đã thấy những cách tiếp cận nào trong thực tế đối với vấn đề này và họ đã thực hiện như thế nào?

Trả lời

4
{ 
_id: messagePrefs_uniqueId, 
type: 'prefs', 
timestamp: unix_timestamp 
ownerId: receipientId, 
messageId: messageId, 
read: true/false, 
} 

{ 
_id: message_uniqueId, 
timestamp: unix_timestamp 
type: 'message', 
contents: 'this is the message', 
senderId: senderId, 
recipients: [receipientId1,receipientId2] 
} 

Giả sử bạn có 3 thông điệp bạn muốn lấy ưu đãi đối với, bạn có thể nhận được chúng qua một cái gì đó như:

db.messages.find({ 
messageId : { $in : [messageId1,messageId2,messageId3]}, 
ownerId: receipientId, 
type:'prefs' 
}) 

Nếu tất cả các bạn cần được đọc/chưa đọc bạn có thể sử dụng điều này với khả năng upsert MongoDB của , vì vậy bạn không tạo prefs cho mỗi thư trừ khi người dùng thực sự đọc nó, sau đó về cơ bản bạn tạo đối tượng prefs với id duy nhất của riêng bạn và upsert nó vào MongoDB. Nếu bạn muốn linh hoạt hơn (như nói thẻ hoặc thư mục), bạn có thể muốn tạo tiền tố cho mỗi người nhận thư. Ví dụ bạn có thể thêm:

tags: ['inbox','tech stuff'] 

vào prefs đối tượng và sau đó để có được tất cả các prefs của tất cả các tin nhắn được gắn thẻ với 'cụ công nghệ cao' bạn muốn đi một cái gì đó như:

db.messages.find({type: 'prefs', ownerId: recipientId, tags: 'tech stuff'}) 

Bạn có thể sau đó sử dụng thông báoBạn tìm thấy trong các prefs để truy vấn và tìm thấy tất cả các thư tương ứng:

db.messages.find((type:'message', _id: { $in : [array of messageIds from prefs]}}) 

Có thể hơi rắc rối nếu bạn muốn làm điều gì đó như đếm bao nhiêu thư mỗi 'thẻ' chứa hiệu quả. Nếu đó chỉ là một số ít thẻ, bạn chỉ có thể thêm .count() vào cuối truy vấn của mình cho mỗi truy vấn. Nếu đó là hàng trăm hoặc hàng ngàn thì bạn có thể làm tốt hơn với kịch bản lệnh máy chủ bản đồ/giảm hoặc có thể là một đối tượng theo dõi số lượng tin nhắn trên mỗi thẻ cho mỗi người dùng.

+1

Cảm ơn, vì vậy đề xuất của bạn về bản chất là cùng một loại bảng 'tuple/join' giống như trường hợp quan hệ, đúng không? Bất kỳ lý do cụ thể nào bạn lưu trữ cả tin nhắn và các prefs trong cùng một bộ sưu tập? –

+0

Điều với MongoDB thường là phẳng hơn bạn có thể làm cho đối tượng của bạn trở nên tốt hơn. Trong khi nó có thể lưu trữ các cấu trúc lồng nhau, nó không phải là tốt nhất tại truy vấn hoặc nhận được vào những cấu trúc sau này để thay đổi chúng. Vì vậy, rất nhiều thứ có thể kết thúc trông giống như một quan hệ, nhưng với ít trừu tượng hơn do không sử dụng các bảng. Ngoài ra không có lý do gì tôi lưu trữ chúng trong cùng một bộ sưu tập khác ngoài việc không thích có một bộ sưu tập bazillion. Nếu bạn có kế hoạch có hàng triệu thư, bạn nên sử dụng các bộ sưu tập khác nhau để bạn có thể thiết lập các chỉ mục để phù hợp với từng đối tượng tốt hơn. – Klinky

3

Nếu bạn chỉ lưu trữ một giá trị boolean đơn giản, như đọc/chưa đọc, một phương pháp khác là nhúng một mảng trong mỗi Tài liệu chứa danh sách Người dùng đã đọc nó.

{ 
    _id: 'document#42', 
    ... 
    read_by: ['user#83', 'user#2702'] 
} 

Sau đó, bạn có thể lập chỉ mục trường đó, thực hiện truy vấn nhanh cho Tài liệu đọc bởi Người dùng và Người dùng đã đọc-Tài liệu.

db.documents.find({read_by: 'user#83'}) 

db.documents.find({_id: 'document#42}, {read_by: 1}) 

Tuy nhiên, tôi thấy rằng tôi thường truy vấn cho tất cả các tài liệu có không được đọc bởi một người dùng đặc biệt, và tôi không thể nghĩ ra bất kỳ giải pháp mà có thể tận dụng các chỉ mục trong này trường hợp.Tôi nghi ngờ không thể thực hiện điều này nhanh chóng mà không cần có cả mảng read_byunread_by để mọi Người dùng được bao gồm trong mọi Tài liệu (hoặc tham gia bảng), nhưng điều đó sẽ có chi phí lưu trữ lớn.

+0

Về điểm cuối cùng về truy vấn cho các tin nhắn * chưa đọc * nhưng sử dụng trường * read_by *, sửa tôi nếu tôi sai nhưng không thể mệnh đề ** $ không ** đạt được điều này, như trong '$ not: {$ in: [{id: 'user # 83'}]} '? – bigp

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