View design advice

38 views
Skip to first unread message

Sebastien ARBOGAST

unread,
Jan 8, 2015, 3:24:32 PM1/8/15
to mobile-c...@googlegroups.com
In my ios app, I have 2 document types:
- a List document type
- an Item document type

A List can contain many Items.
A lot of instances of my app can add items to the list at the same time, and all instances are synchronized with sync gateway, so to avoid dealing with conflicts, I chose to store Lists and Items in 2 different document types instead of embedding items into lists. Maybe I was wrong, but that's the way it works now.

I defined a view to display all the Lists sorted by creation date:

var listsView = database.viewNamed("listsView")
listsView.setMapBlock({ (doc, emit) -> Void in
    if doc["type"] as? String == "list" {
        emit(doc["date"], nil)
    }
}, version: "1")

And Item documents have a "list" property that contains the documentID of the list that contains it.

All this works well.

But now in the viewcontroller that displays all the Lists, for each List, I would like to display the number of Items that are associated with it.

Is there any way that I can modify my view so that it serves both to filter list-type documents and keep track of the number of list-items in it?

Thx in advance,

---
Sébastien Arbogast
http://sebastien-arbogast.com

Jeremy Kelley

unread,
Jan 8, 2015, 3:33:15 PM1/8/15
to mobile-c...@googlegroups.com
You could have a view that iterates over list-items and emits the
listid and count. Then do a reduce on that with grouplevel=1.

This will provide you a view of all lists that have at least one item
and is basically a count, "group by".

-j
> --
> You received this message because you are subscribed to the Google Groups
> "Couchbase Mobile" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to mobile-couchba...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/mobile-couchbase/CAG1DMa_orDOUdNjw7_yCAQ78mg6nyzNZQQ17Jqt3qeZAbQhF7g%40mail.gmail.com.
> For more options, visit https://groups.google.com/d/optout.



--
The Christian ideal has not been tried and found wanting;
it has been found difficult and left untried – G. K. Chesterton

Jens Alfke

unread,
Jan 8, 2015, 4:38:40 PM1/8/15
to mobile-c...@googlegroups.com

On Jan 8, 2015, at 12:24 PM, Sebastien ARBOGAST <sebastien...@gmail.com> wrote:

But now in the viewcontroller that displays all the Lists, for each List, I would like to display the number of Items that are associated with it.

That's a straightforward example of grouping & reducing. I talked about this in one of my Couchbase Connect presentations last year; here's the link.

In a nutshell, your view's map function emits keys of the form [listID, itemDate], and the reduce function returns the number of values (values.count). Then you set the query's groupLevel to 1. In the query result each row will contain a list ID and the number of items in the list.

—Jens

Sebastien ARBOGAST

unread,
Jan 8, 2015, 4:53:15 PM1/8/15
to mobile-c...@googlegroups.com
OK, so if I understand correctly, I would define my view like this:

var listsView = database.viewNamed("listsView")
listsView.setMapBlock({ (doc, emit) -> Void in
    if doc["type"asString == "item" {
        emit([doc["list"], doc["date"]], nil)
    }
}, reduceBlock: { (keys, values, rereduce) -> AnyObject! in
    return values.count   
}, version: "1")

Is that correct?
And if it is, doesn't that mean that my grouped query will only show listID that are associated to at least 1 item. All the Lists that don't have any sub-items will not be represented in this list, right?
Is it possible to get a list of list IDs and number of items in each list, the number being 0 if there is no item associated with this list?

---
Sébastien Arbogast
http://sebastien-arbogast.com

--
You received this message because you are subscribed to the Google Groups "Couchbase Mobile" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mobile-couchba...@googlegroups.com.

Sebastien ARBOGAST

unread,
Jan 8, 2015, 5:12:21 PM1/8/15
to mobile-c...@googlegroups.com
Actually I just kept watching the video and what I'm trying to achieve seems very similary to the post/comments example, so I'll try that pseudo-join thing and see how it goes.

---
Sébastien Arbogast
http://sebastien-arbogast.com

Jens Alfke

unread,
Jan 8, 2015, 5:37:37 PM1/8/15
to mobile-c...@googlegroups.com

On Jan 8, 2015, at 1:52 PM, Sebastien ARBOGAST <sebastien...@gmail.com> wrote:

Is it possible to get a list of list IDs and number of items in each list, the number being 0 if there is no item associated with this list?

Yeah — add a few lines to the map function so if doc.type=="list" it will emit [doc._id, ""]. That way every list intersperses its own index entry with a null timestamp. Then the reduce function should return values.count-1.

—Jens

Sebastien ARBOGAST

unread,
Jan 8, 2015, 5:54:20 PM1/8/15
to mobile-c...@googlegroups.com
OK, so for future reference, here is the Swift code for my view and it works great.

var listsView = database.viewNamed("listsView")

listsView.setMapBlock({ (doc:[NSObject : AnyObject]!, emit) -> Void in
    switch doc["type"] as String {
        case "list": emit(doc["_id"], doc["date"])
        case "item": emit(doc["list"], "") 
        default: return
    }
}, reduceBlock: { (keys:[AnyObject]!, values:[AnyObject]!, rereduce:Bool) -> AnyObject! in
    var date:AnyObject = values.filter({ (x) -> Bool in
        return x as? String != ""
    })[0]
    return [date, values.count - 1]
}, version: "1")

Now I don't want to ask for too much, but is there any way that I can sort the results by list date, or do I have to do this manually after I get the query result?


---
Sébastien Arbogast
http://sebastien-arbogast.com

--
You received this message because you are subscribed to the Google Groups "Couchbase Mobile" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mobile-couchba...@googlegroups.com.

Jens Alfke

unread,
Jan 8, 2015, 7:19:15 PM1/8/15
to mobile-c...@googlegroups.com

On Jan 8, 2015, at 2:53 PM, Sebastien ARBOGAST <sebastien...@gmail.com> wrote:

Now I don't want to ask for too much, but is there any way that I can sort the results by list date, or do I have to do this manually after I get the query result?

No, you can't. An index can sort by one primary key, and in this case the primary key has to be the list ID, in order to group all the items with the same list together. So you can't also sort by date.

But you can get the reduce function to return both the item count and the mod date (it's the second item of the first value) for each list, which makes them easy to sort by setting the sortDescriptor property of the query.

—Jens

Reply all
Reply to author
Forward
0 new messages