简体   繁体   中英

What is the most efficient approach to get posts that were not voted by an user, on CouchBase?

I have a bucket with posts on the following format:

{title:"foo", 
description:"bar", 
votes: {John:1, Leo:-1, ...}}

I will be continuously querying for posts that have less than N votes and that weren't voted by a specific user yet. The problem is: I can't make views for every specific user, so I have to set one to filter posts with <50 votes and then programatically filter those that weren't voted by the specific user. Is that the correct way to approach this issue?

If you have many users that can vote, you shouldn't use your approach because to add a vote you need to:

  1. Get document
  2. Parse json into some structure
  3. Add some vote to vote array
  4. Write object back to base

So if someone else vote between 1 and 4 steps, and you don't check CAS on write back, that vote will be lost. And if you check CAS and votes come very fast you can get very slow performance.

The solution is, as I said before, to save votes separatly in JSON like:

{
  "type":"vote",
  "voterId": 123,
  "votedFor": 321,
  "timestamp": 131321321
}

And store your items without votes, like this:

{
  "type":"item",
  "itemId": 321,
  "title": foo
}

With this scheme you work only with votes when you need to count them, see what users voted for some item, etc.

Another trick: if you need to display votes, ie on your website, you can also have "fast_voutes_count". This means that you can create separate variable that will store only votes count per item: votes:count:for:<itemId> . And if someone votes item you should:

  1. Increment item vote count value by key: votes:count:for:<itemId>
  2. Store user's vote as vote document ( {"type":"vote","voterId": 123,"votedFor": 321, "timestamp": 131321321} ).

So first value will be used to display votes on a website. And the second one will be used for counting your statistics.

For creating view that you need (map,reduce functions) you can refer to this manual and it's examples. If you're new to map/reduce firstly try to create a view that will display votes only for specific itemId, here is small example:

map: 
function(){
  if (meta.type === "json" && doc.type === "vote"){
    emit(doc.votedFor, null);
  }
}

Then if you want to count (sum) that votes just use _count as reduce function.

PS: In my application, we use such approach to count views for videos: one key-value called "fast_clip_view" is used for displaying info on website and another detailed clipview with userId , clipId and timestamp for detailed stats.

By the way, if you'll need something like "Top 10 items by votes" refer to this question .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM