We recently upgraded to Couchbase v2.1.4 from Couchbase v1.3.9. The way to query views changed significantly and I can’t get the objects to deserialize when running a query of a view like this:
var query = bucket.CreateQuery(designDoc, viewName, false); var result = bucket.Query<MyType>(query); foreach (var row in result.Rows) { // row.Id and row.Key are set properly, but... // row.Value is always null. }
We are getting back the correct number of rows, but each row always has a value of “null.” I can use any of the returned keys and call this and it returns a hydrated instance of MyType:
var result = bucket.Get<MyType>(key);
I thought it might be a Newtonsoft.Json issue at first. We’re using Newtonsoft.Json v8.0.2. I tried the following and was able to deserialize the document successfully:
var result = bucket.Get<string>(key); var json = result.Value; var actual = JsonConvert.DeserializeObject<MyType>(json);
I’m running out of ideas as to why the row Value property is always null. Is this a bug or am I implementing the query incorrectly?
@bfederici
Can you provide your MapReduce javascript for your view? And maybe a screenshot of the sample output from the development designer in the web portal? That might help me understand the output format of your view and how that corresponds to your view request.
Thanks,
Brant
Here is the simple map function:
function (doc, meta) { if (doc.Score >= 200 && !doc.Deactivated) { emit(meta.id, null); } }
The view results in the web portal all show a value of “null” as well, but the documents contain valid JSON. Do I need to emit the “doc” in the map function?
@bederici
Okay, so the behavior is the result of your view script. Note that the second parameter to emit is null. This is the value that is returned in the Value property when you query the view.
So, you have two routes to address this issue:
-
Change “null” to “doc” in the view script. This will include the document in the view. Downside to this approach is that it increases storage requirements because the document is stored in both the main store and in the view itself. Upside is that you can get the answer with a single query. This is usually best for small documents.
-
Change your .NET SDK usage. Get the view results first, like you do now. Then use the return Key to hydrate the main document object after the view result returns. This is usually better for larger documents or scenarios when speed is less important than data size on your cluster.
Very rough example, needs error handling, testing, etc:
var query = bucket.CreateQuery(designDoc, viewName, false);`
var result = bucket.Query<object>(query);
var hydrated = bucket.Get<MyType>(result.Rows.Select(p => p.Key)).ToArray());
Thanks,
Brant
1 Like
Thanks for the helpful response, @btburnett3. The index doesn’t contain a large number of documents, so I’ll emit the document.
1 Like