side note
Upgrading octopress is a @!#!@pain! :>
What is this post about :)
Long time nothing new here so i will glue something together about stuff that we were talking about today with my friend Jarek. We talked about building backend for Todo app :). Yes simple todo app. How to build scalable backend. So my initial thought was “how i would design it in different databases”. (i’m taking only about data model)
Requirements
What we know:
- User has some sort of id. (number, email, hash of something)
- We need to be able to have different todo lists
- User can choose his todo list and see tasks ( obvious )
- User can tag tasks!
- User can query tasks in list by tags
- User can see all tags.
Design using Redis
How to do it with redis ? :)
First few facts i assumed at start. Single todo task has body and timestamps [created_at, updated_at] and base for key will be phrase “todoapp”.
So lets start with user and his list of todo lists :). This gives us first key
1 2 3 |
|
Here we have two keys, first is list id counter that we will bump to get new list counter :), second is list of todolists ids. Why do it this way ? Well people can add and remove todo lists.
Ok so how to create new list ?
1 2 3 4 5 6 7 8 |
|
Hey ! we just added id of our first list to list of our todo lists (lots of list word here!). Ok so now lets add a task.
list:
1 2 |
|
and task:
1 2 3 |
|
Ok so how to i add task to my list
1 2 3 4 5 6 7 8 9 10 |
|
And we have our first task in. How do we get tasks from out todo list simple!
1 2 3 4 5 6 |
|
Ok so now we have very simple todo lists with tasks, well at least overview. Ofc you can use sets for todo lists or zsets but lets stay with lists to keep it simple for now.
How ro remove task from the list ?
1 2 3 4 |
|
Good, now we can add tasks, remove tasks, same sotry with adding todo lists and removing todo lists. One last thing is to add tags!. Simply here each task will have list of tags and each tag will have list of tasks related with.
1 2 |
|
So how we will add tags to tasks ? Simple!
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
This example shows what we need to do to tag a task with something and how to peek tasks tagged with it. Why we have both lists ? To make it fast while searching. If user will click on particular tag like “redis” you want to get it O(1) time not O(N) after searching all keys. And same the other way, normal ui will pull task test, when it was created and tags to display so we want to have this data ready.
This is whole design for the todo app. We have 8 types of keys. Things like pagination, calculating time are all left to app layer. Important thing is that i scope everything to user key / id. This is because i want to isolate each user space easy. Each user in his own space will have short lists, there is no danger of “ultimate” non splittable lists.
Design using Mongodb
Well this case upfront is easier to grasp because for each list we can use single document or collection of documents lets talk about both solutions.
Todolist = Document
In this example we will use built in “array” operators
1 2 3 4 5 6 7 |
|
So lets add a task :)
1 2 3 4 5 6 7 8 9 |
|
this will create empty todo list with name “House work” of course this way we will not omit building sub lists of tags etc, we have to build in a same way like in redis but as part of document. The story is exactly the same like above in redis. Mongodb lets us query nested documents and this will enable us to skip some of the extra “lists” while doing search.
Lets try it out how to find out mongo tagged entries?
1 2 3 4 5 6 7 8 |
|
This way we can find whole todolist with task that contains tag “mongo” but after that we will have to work out from the document in app the task that we are interested int. Using it like this we will have a document with structure like this
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Using redis we could wrapp stuff into MULTI command while using mongodb “array” command we are a bit cowboishing. They could remove wrong stuff in we will not be cautious :). (well same in redis!) Big plus of Mongodb is native time type!
Todolist = many documents
Using this approach we can leverage more of our stuff on mongodb search in this approach each task will be a different document. With structure like this
1 2 3 4 5 6 |
|
This way we will have a lot of documents, more disk space consumption and still we will have to have second collection with with objects with structure like this
1 2 3 4 5 6 |
|
And this way we can use find
tool very easy and get documents fast.
Summary
All of this solutions have some pros and cons, mongodb excels better when documents are bigger (limit is set on 16 mb per document) than loads of small documents (massive waste of space). Solution in redis is really fast and if you will implement lazy loading it will be very fast. You can adjust this designs to your situation by changing lists to sets etc. The place where redis OWNS mongodb in this context is “strucutres” and we use a lot of them to store data like this, lists sets, zsets. Implementing priority list in mongodb will be totally custom solution while in redis we can just use zset.
This is just my point of view on this. I will supply some code to cover it more in part two. This is next problem, i’m sure solution in mongodb using things like mongoid http://mongoid.org will be much more developer friendly then building things “rawly” in redis hiredis client.
btw i jsut wrote this from “top of my head” so it may contain typos and i’m sure keys, structures can be optimized :) This is just to open discussion with my friend :)
Cheers!