2

Say I have a doc to save with couchDB and the doc looks like this:

{
   "email": "lorem@gmail.com",
   "name": "lorem",
   "id": "lorem",
   "password": "sha1$bc5c595c$1$d0e9fa434048a5ae1dfd23ea470ef2bb83628ed6"
}

and I want to be able to query the doc either by 'id' or 'email'. So when save this as a view I write so:

db.save('_design/users', {
    byId: {
        map: function(doc) {
            if (doc.id && doc.email) {
                emit(doc.id, doc);
                emit(doc.email, doc);
            }
        }
    }
});

And then I could query like this:

db.view('users/byId', {
    key: key
}, function(err, data) {
    if (err || data.length === 0) return def.reject(new Error('not found'));
    data = data[0] || {};
    data = data.value || {};

    self.attrs = _.clone(data);
    delete self.attrs._rev;
    delete self.attrs._id;

    def.resolve(data);
});

And it works just fine. I could load the data either by id or email. But I'm not sure if I should do so.

I have another solution which by saving the same doc with two different view like byId and byEmail, but in this way I save the same doc twice and obviously it will cost space of the database.

Not sure which solution is better.

Ivan Krechetov
  • 18,802
  • 8
  • 49
  • 60
fraserxu
  • 420
  • 3
  • 8

3 Answers3

5

The canonical solution would be to have two views, one by email and one by id. To not waste space for the document, you can just emit null as the value and then use the include_docs=true query paramter when you query the view.

Also, you might want to use _id instead of id. That way, CouchDB ensures that the ID will be unique and you don't have to use a view to loop up documents.

Kim Stebel
  • 41,826
  • 12
  • 125
  • 142
  • It works for me now. Thanks. But also need to note that there's a little different while query the doc with the key that emit with `null`. Since we set the `doc` to null when saving, so when we query the return `value` is also null, but we can get the real data with something like `result[0].data`. – fraserxu Jul 02 '13 at 06:23
1

I'd change to the two separate views. That's explicit and clear. When you emit the same doc twice in a single view – by an id and e-mail you're effectively combining the 2 views into one. You may think of it as a search tree with the 2 root branches. I don't see any reason of doing that, and would suggest leaving the data access and storage optimization job to the database.

The views combination may also yield tricky bugs, when for some reason you confuse an id and an e-mail.

Ivan Krechetov
  • 18,802
  • 8
  • 49
  • 60
1

There is absolutely nothing wrong with emitting the same document multiple times with a different key. It's about what makes most sense for your application.

If id and email are always valid and interchangeable ways to identify a user then a single view is perfect. For example, when id is some sort of unique account reference and users are allowed to use that or their (more memorable) email address to login.

However, if you need to differentiate between the two values, e.g. id is only meant for application administrators, then separate views are probably better. (You could probably use a complex key instead ... but that's another answer.)

Matt Goodall
  • 1,682
  • 10
  • 7
  • My scenario is that I'm implementing a user registration process. The user provide his email address and then we send back a registration link to their mailbox and finally confirm the whole process. But before send them the email we need to check if the email has registered before and that's why I want to use `email` as the key to query the user data in addition to use `id` (obviously we don't have the id before really register). – fraserxu Jul 02 '13 at 04:04