2012-07-03 27 views
7

Cho phép nói rằng tôi có một trang web như digg.com Tôi đã có một loạt bài viết và mọi người có thể bỏ phiếu cho các bài viết họ thích.MongoDB Schema Design - Biểu quyết về bài viết

Tôi muốn có thể truy vấn để nhận các bài viết có nhiều phiếu nhất trong một thời gian nhất định (giờ trước, ngày cuối cùng, tuần trước) được sắp xếp theo số phiếu bầu.

Như thường lệ với MongoDB, có một số cách khác nhau để thực hiện điều này, nhưng tôi không chắc là cái nào là đúng.

  • Một tài liệu viết, trong đó có một mảng của Votes - số phiếu bầu chính họ là tài liệu có chứa userid, tên người dùng và ngày bỏ phiếu:
{ 
    "_id": "ObjectId(xxxx)", 
    "title": "Post Title", 
    "postdate": "21/02/2012+1345", 
    "summary": "Summary of Article", 

    "Votes": [ 
     { 
      "userid":ObjectId(xxxx), 
      "username": "Joe Smith", 
      "votedate": "03/03/2012+1436" 
     }, 
      ] 
    } 
  • Một bộ sưu tập phiếu riêng biệt, chứa thông tin chi tiết của một cá nhân bỏ phiếu và tham chiếu đến bài đăng đã được bỏ phiếu trên:
{ 
    "_id": "ObjectId(xxxx)", 
    "postId": ObjectId(xxxx), 
    "userId": ObjectId(xxxx), 
    "votedate": "03/03/2012+1436" 
} 

Tài liệu đầu tiên là Documentey nhiều hơn nhưng tôi không biết cách truy vấn mảng phiếu để nhận các tài liệu có nhiều phiếu bầu nhất trong 24 giờ qua.

Tôi đang nghiêng về phía thứ hai vì sẽ dễ dàng hơn để truy vấn số phiếu bầu được nhóm theo phiếu tôi nghĩ, nhưng tôi không chắc nó sẽ hoạt động tốt như thế nào. Đây là cách bạn muốn làm điều đó trong Cơ sở dữ liệu quan hệ, nhưng nó không có vẻ rất tài liệu - nhưng tôi không chắc chắn nếu nó là một vấn đề, phải không?

Hoặc tôi có sử dụng kết hợp cả hai không? Ngoài ra, tôi sẽ làm loại truy vấn tổng hợp này trong thời gian thực, mỗi lần tải trang. Hay tôi chỉ chạy truy vấn nói một lần mỗi phút và lưu trữ kết quả trong bộ sưu tập kết quả truy vấn?

Bạn sẽ triển khai giản đồ này như thế nào?

+0

câu hỏi liên quan: http://stackoverflow.com/questions/ 9296793/hiệu quả-document-format-to-store-phiếu-trong-mongo-db –

+0

Cũng liên quan: http://stackoverflow.com/questions/7046462/best-way-to-model-a-voting-system-in -mongodb – wmassingham

Trả lời

9

Cách phổ biến để theo dõi số lượng phiếu bầu tổng thể sẽ là giữ số phiếu bầu trong tài liệu bài đăng và cập nhật nó một cách nguyên tử khi đẩy một giá trị mới vào mảng phiếu bầu.

Vì đây là bản cập nhật duy nhất, bạn được đảm bảo rằng số lượng sẽ khớp với số phần tử trong mảng.

Nếu số lượng tập hợp cố định và trang web rất bận, bạn có thể mở rộng mô hình này và tăng thêm bộ đếm, giống như một tháng, ngày và giờ, nhưng điều đó có thể nhanh chóng hết. Vì vậy, thay vào đó bạn có thể sử dụng mới (có sẵn trong bản phát hành 2.1.2 dev, sẽ được sản xuất trong bản phát hành 2.2. Đơn giản hơn là sử dụng Map/Reduce và nó sẽ cho phép bạn thực hiện các phép tính mà bạn muốn rất đơn giản. cẩn thận lưu trữ ngày bỏ phiếu của bạn dưới dạng ISODate().

đường ống tiêu biểu cho truy vấn tập hợp cho thu khí bầu cử đầu tháng này có thể trông như thế này:

today = new Date(); 
thisMonth = new Date(today.getFullYear(),today.getMonth()); 
thisMonthEnd = new Date(today.getFullYear(),today.getMonth()+1); 

db.posts.aggregate([ 
    {$match: { "Votes.votedate": {$gte:thisMonth, $lt:thisMonthEnd} } }, 
    {$unwind: "$Votes" }, 
    {$match: { "Votes.votedate": {$gte:thisMonth, $lt:thisMonthEnd} } }, 
    {$group: { _id: "$title", votes: {$sum:1} } }, 
    {$sort: {"votes": -1} }, 
    {$limit: 10} 
]); 

Điều này hạn chế đầu vào cho các đường ống để bài viết có phiếu theo ngày bỏ phiếu phù hợp với tháng bạn đang đếm , "thư giãn" mảng để nhận một tài liệu cho mỗi phiếu bầu và sau đó thực hiện "nhóm theo" tương đương tổng hợp tất cả các phiếu bầu cho mỗi tiêu đề (tôi giả sử tiêu đề là duy nhất). Sau đó nó sắp xếp giảm dần theo số phiếu bầu và giới hạn đầu ra thành mười lần đầu tiên.

Bạn cũng có khả năng tổng hợp phiếu bầu vào ban ngày (ví dụ) cho tháng đó để xem những ngày này là tích cực nhất cho bầu cử:

db.posts.aggregate([ 
    {$match: { "Votes.votedate": {$gte:thisMonth, $lt:thisMonthEnd} } }, 
    {$unwind: "$Votes" }, 
    {$match: { "Votes.votedate": {$gte:thisMonth, $lt:thisMonthEnd} } }, 
    {$project: { "day" : { "$dayOfMonth" : "$Votes.votedate" } } }, 
    {$group: { _id: "$day", votes: {$sum:1} } }, 
    {$sort: {"votes": -1} }, 
    {$limit: 10} 
]); 
+0

nếu bạn kết thúc việc lưu trữ phiếu bầu trong bộ sưu tập của riêng mình thay vì nhúng vào bài đăng, thì bạn sẽ không cần bước "thư giãn", phần còn lại của tập hợp về cơ bản vẫn giữ nguyên. –

+0

lưu ý rằng không phải ngẫu nhiên mà tôi $ khớp với tháng mong muốn hai lần. Trận đấu $ đầu tiên loại bỏ các bài đăng không có bất kỳ phiếu bầu nào trong tháng mong muốn, nhưng trận đấu thứ hai $ (sau khi $ relax) đảm bảo chúng tôi chỉ giữ phiếu bầu đã xảy ra trong tháng đó trước khi chúng tôi đếm chúng. Trận đấu $ đầu tiên có để giảm số lượng tổng số tài liệu mà chúng tôi đang đưa vào đường ống, điều đó không thực sự cần thiết ngoại trừ hiệu suất. –

+0

Tôi đang cố gắng sử dụng giải pháp cho các tài liệu được tham chiếu, nhưng nó không hoạt động. Trong bài kiểm tra của tôi, tôi có 6 bài đăng và chỉ một bài đăng có một phiếu bầu. Tất cả những người khác không có hồ sơ trong bộ sưu tập 'posts_votes'. Nếu tôi chạy '{$ group: {_id:" $ votes.post_id ", số phiếu: {$ sum: 1}}}' Tôi lấy lại một bản ghi với một _id null. Nếu tôi thay đổi '$ votes.post_id' thành' $ title', nó trả về tất cả 6 bài viết với một phiếu bầu (chỉ nên có một bài đăng với một phiếu bầu, tất cả những người khác có số không). Ngoài ra, hãy thử thêm mảng '$ project' để tạo biến bằng cách sử dụng' $ votes.post_id' – Nathan

0

Lược đồ bạn chọn phụ thuộc phần lớn vào trường hợp sử dụng của bạn..Nếu bạn đang mong đợi nhiều phiếu bình luận và muốn xử lý chúng độc lập với bài đăng, bạn có thể giữ chúng trong một bộ sưu tập riêng biệt với postID Tuy nhiên, nếu bạn muốn tải tất cả các phiếu bầu khi bạn tải một bài đăng cụ thể và các phiếu bầu trong chính họ không có bất kỳ ý nghĩa nào nếu không có bài đăng chứa chúng, sau đó đi nhúng (trong trường hợp, cách tiếp cận đầu tiên).

+0

Bạn có thể thử mapreduce với phương pháp tiếp cận tài liệu hơn để truy vấn mảng phiếu bầu để nhận các tài liệu có nhiều phiếu nhất trong 24 giờ qua ... Vì mapreduce xảy ra là một hoạt động nặng, tốt hơn nên chạy nó thỉnh thoảng và sử dụng kết quả được lưu trong bộ nhớ cache. –

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