Create a view in Cloudant (CouchDB) based on an object property value

I am trying to find a solution for this requirement, but I have hit a lot of dead ends.

I use Cloudant as a repository of user document data. Each user document has a field (property) called "elements", which is an array of objects.

So, the user document is as follows:

{ "_id":"userid1", "_rev":"XX", "username": "foobaruser" "items": [ { "date":1357879144069, "text":"don't cry because it 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" } ] } 
  • There are several user documents in the data warehouse, and each document has the "items" property

Requirements:

  • Ideally, I would like to use the search function in the view and pass in the value for "cat", which then returns all the "elements" in all documents matching the value of "cat".

    eg. Https: // [username] .cloudant.com / dbname / _design / views / _search / doc d = definition

  • The above search returns all objects in the "elements" in all user documents that have "cat = definition" in a format like this:

     { "total_rows": 2, "rows": [{ "id": "userid1", "items": [ { "date":1357879144069, "text":"don't cry because it 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", can secondary indexes be used to achieve this?

+4
source share
3 answers

In CouchDB, you cannot pass the dynamic value of a query parameter into a view (in your case cat = definition). 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 the data you need.

To achieve this, you need to create a custom view in the db design document:

 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}); } } } 

Thus, the above view takes every doc in db, checks that it has an array of elements with content, and then iterates over all the elements of the document. For each element of the element, he finds that he emits cat into the result set as an index, this is important, since we can sort against this index. We can build the result object in any case (the second argument is emit ), and in this case I create an object with a user ID, as well as the date and text of the element.

You would name 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 results in which a key parameter (i.e. cat ) would be a "definition":

 curl -X GET http://127.0.0.1:5984/<db-name>/_design/<design-doc-name>/_view/byUserItemCat?key="determination" 
+5
source

Searching in the cloud works with the detail of returning a document. The index function can index the categories used in item in a document, and then your search will return documents containing item with the category you specify. Then your application code will need to filter to item to return to the client.

Your index function will be something like (shamelessly compressed 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"}); } 

An alternative is to split elements into your own documents if you really want to get only elements.

However, I would have given Wintamute a second (and received approval) answer, since I agree that the proposed view is the best solution in this particular case (find and map elements to cat ).

+1
source

This can be done using a search in Cloudant. I had a similar problem that I needed to solve. Special thanks to Mike Breslin in Oblagant for help.

 function(doc){ if (doc.items) { for (var n in doc.items) { if (doc.items[n].cat) { index("cat", doc.items[n].cat, { store : true }); } } } } 

You can request it when searching as:

 ?q=cat:hardwork OR cat:determination 
+1
source

All Articles