I've been trying to find a solution for this requirement but I've hit many dead ends.
I'm using Cloudant as my data store of user documents. Each user document has a field (property) called 'items', which is an array of objects.
So a user document looks like this:
{
"_id":"userid1",
"_rev":"XX",
"username": "foobaruser"
"items":
[
{
"date":1357879144069,
"text":"don't cry because it's over, smile because it happened.",
"cat":"determination"
},
{
"date":1357879179209,
"text":"those who mind don't matter, and those who matter don't mind.",
"cat":"fitness"
},
{
"date":1357883809736,
"text":"be the change that you wish to see in the world.",
"cat":"determination"
},
{
"date":1357879179209,
"text":"those who mind don't matter, and those who matter don't mind.",
"cat":"hardwork"
},
{
"date":1357879179209,
"text":"those who mind don't matter, and those who matter don't mind.",
"cat":"determination"
}
]
}
Requirement:
Ideally, i'd like to use a search function on a view and pass in a value for "cat", which then returns all the "items" in all docs that match the value of "cat".
e.g. https://[username].cloudant.com/dbname/_design/views/_search/doc?q=determination
The above search will return all the objects in "items" across all user docs which have "cat = determination" in a format similar to this:
{
"total_rows": 2,
"rows":
[{
"id": "userid1",
"items":
[
{
"date":1357879144069,
"text":"don't cry because it's over, smile because it happened.",
"cat":"determination"
},
{
"date":1357883809736,
"text":"be the change that you wish to see in the world.",
"cat":"determination"
},
{
"date":1357879179209,
"text":"those who mind don't matter, and those who matter don't mind.",
"cat":"determination"
}
]
},
{
"id": "userid2",
"items":
[
{
"date":135787966655,
"text":"Some text",
"cat":"determination"
}
]
}]
}
If this is not possible using "search", then is it possible to use secondary-indexes to achieve this?
In CouchDB you can't pass in a dynamic value for a query parameter to a view (in your case cat=determination). The approach in CouchDB is to create a more general view, and then adjust how the result is sorted when you call the view to get at the data you need.
You'll need to create custom view in your db's design document to achieve this:
byUserItemCat: {
map: function (doc) {
if ( !doc.items || doc.items.length === 0 ) return;
for ( var i=0; i<doc.items.length; i++ ) {
emit(doc.items[i].cat,{doc._id,doc.items[i].date,doc.items[i].text});
}
}
}
So the above view takes each doc in the db, checks it has an items array with contents, and then loops over all the doc's items. For each item element it finds it emits cat
into the result set as the index, this is important since we can then sort against against this index. We're free to build the result object in anyway we like (second argument to emit
), and in the above case I'm building an object with the user id, and the item's date and text.
You'd call the view something like this, to get all the results:
curl -X GET http://127.0.0.1:5984/<db-name>/_design/<design-doc-name>/_view/byUserItemCat
And if you were just interested in the results where the index key (i.e. cat
) was "determination" you'd do:
curl -X GET http://127.0.0.1:5984/<db-name>/_design/<design-doc-name>/_view/byUserItemCat?key="determination"
Cloudant's search works at the granularity of returning a document. Your indexing function could index the categories in use across the item
s in the document and then your search would return the documents containing item
s with the category you mention. Your application code would then need to filter down to the item
s to return to the client.
Your index function would be something like (shamelessly cribbing from Wintamute):
if (!doc.items || doc.items.length === 0) return;
var item;
for (var i=0; i<doc.items.length; i++) {
index("cat", doc.items[i].cat, {"index": "not_analyzed"});
}
The alternative is to break out the items into their own documents if you really want to be able to get just the items.
However, I'd second (and have up-voted) Wintamute's answer as I agree that the suggested view is the best solution in this specific case (find and display items by cat
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With