Search code examples
javajsonviewcouchdbcloudant

Cannot retrieve JSON value


I have the following view

{
  "views" : {
    "categories" : {
      "map" : "function (doc) {  emit(doc._id,{"title":doc.title,"parentnode":doc.parentnode});}"
    }
  }
}

i.e., for each document, return a JSON object with two keys : title and parentnode with their respective values. The view runs just fine in the cloudant UI

{
 "id": "3bacce314363eb954f1922ff3cd2240c",
 "key": "3bacce314363eb954f1922ff3cd2240c",
 "value": {
  "title": "poi",
  "parentnode": "asd"
 },
 "_id": "3bacce314363eb954f1922ff3cd2240c"
}

which is perfect. Now i try to read this in my Java program as

List<JSONObject> vals = cloudant.getViewRequestBuilder("categoryDesign", "categories")
.newRequest(com.cloudant.client.api.views.Key.Type.STRING, JSONObject.class)
.includeDocs(true)
.build()
.getResponse()
.getValues();

Note that JSONObject in this case is org.json.JSONObject;. But for this i get

[{}]

so then i changed the view a little bit

{
      "views" : {
        "categories" : {
          "map" : "function (doc) {  emit(doc._id,doc.title+":"+doc.parentnode);}"
        }
      }
    }

and in the cloudant UI i see

{
 "id": "9db1f03e8f4d239a6e18d4612b1a4275",
 "key": "9db1f03e8f4d239a6e18d4612b1a4275",
 "value": "poi:asd",
 "_id": "9db1f03e8f4d239a6e18d4612b1a4275"
}

and now i do

List<String> vals = cloudant.getViewRequestBuilder("categoryDesign", "categories")
.newRequest(com.cloudant.client.api.views.Key.Type.STRING, String.class)
.includeDocs(true)
.build()
.getResponse()
.getValues();

Now, the output is

["poi:asd"]

What can i do to read the values as JSONObjects ?

Follow Up: How can i remove the duplicates from the output of the view?


Solution

  • Cloudant client does not seem to work with org.json.JSONObject. I got your first example to work with com.google.gson.JsonObject and org.apache.wink.json4j.JSONObject. Here are the maven dependencies:

    com.google.gson.JsonObject:

    <dependency>
       <groupId>com.google.code.gson</groupId>
       <artifactId>gson</artifactId>
       <version>2.7</version>
    </dependency>
    

    org.apache.wink.json4j.JSONObject:

    <dependency>
       <groupId>org.apache.wink</groupId>
       <artifactId>wink-json4j</artifactId>
       <version>1.4</version>
    </dependency>
    

    Output from System.out.println(vals.toString()):

    [{"parentnode":"asd","title":"poi"}]
    

    To answer the followup question:

    You can eliminate duplicates by using a reduce function (sum or count) in your view, but this also would require that you change your key to be the unique key for the data. So, if the combination of title and parentnode is what you want to be your unique key, your view would look like this:

    "categoriesNoDups": {
       "reduce": "_sum",
       "map": "function (doc) { emit([doc.title, doc.parentnode], 1); } }"
    }
    

    Now, when you call your view (note the new view is named categoriesNoDups) you want to add ?group=true like so:

    https://youraccount.cloudant.com/yourdb
    /_design/categoryDesign/
    _view/categoriesNoDups?group=true
    

    The data will look similar to the following:

    {
      "rows": [
        {
          "key": [
            "poi",
            "asd"
           ],
           "value": 2
        }
      ]
    }
    

    Now, instead of getting the values you want to get the keys. To retrieve the keys in Java you would do something like this:

    List<Key.ComplexKey> keys = cloudant.getViewRequestBuilder("categoryDesign", "categoriesNoDups")
       .newRequest(Key.Type.COMPLEX, Number.class)
       .group(true)
       .build()
       .getResponse()
       .getKeys();
       for (Key.ComplexKey key : keys) {
           JSONArray keyValues = new JSONArray(key.toJson());
           System.out.println("title = " + keyValues.getString(0));
           System.out.println("parentnode = " + keyValues.getString(1));
       }
    

    Now you're back to dealing with arrays instead of JSON objects. Also note: I am using the Apache Wink JSON library to convert the keys to JSON objects (which are just arrays) and then accessing the values from those objects. The output looks similar to the following:

    title = poi
    parentnode = asd