lookupIn operation fails when any path is missing

I am using the Node.js SDK 2.6.x to interact with a Couchbase 6.0.x cluster. I am able to chain multiple .get(‘pathname’) provided all of the paths exist.

I am seeking how to deal with missing paths using the bucket.lookupIn operation.

When any one of the paths are missing, the whole operation fails. I was expecting the operation to succeed and either ignore the missing path or return null or undefined for it. Below is a facsimile of my implementation:

bucket.lookupIn(doc.id)
.get('path1')
.get('path2')
.get('path2')
.execute(...)

If any of the paths are empty, the SDK raises an error value of “1”

I understand there is the .exists(‘pathname’) but how may one utilize this to get the value if it does exists? How should one handle missing paths?

Regards,

Jay

@ebishard can you please assist ?

@AV25242 - any luck finding someone to answer this? Our effort to reduce the amount of N1QL we are leveraging is blocked.

Jay.

@MikeGoldsmith - I read you mentioning the lookupInBuilder in your reply to a separate issue. Would you have some insight how I can move past this blocker of mine cited above?

Hey @The_Cimmerian ,

Have you checked if the result is still returned even when the err field contains 1? Additionally, have you tried using the 3.x SDK? It has improved the sub-document interfaces quite a bit.

Cheers, Brett

I appreciate the response, @brett19

The error is being caught first in the .execute error block then bubbles up to the outer “http” function illustrated below.

As mentioned the implementation below works when all the referenced fields are present. It throws errors at the first referenced field it finds missing. So, I don’t see anything but the error which is simply “1”.

As to switching SDK:
I have reviewed the compatibility grid and it appears I should be able to do this. Can you confirm that I can merely swap out the SDK 2.6.x we are using with the 3.x and all existing implementation of 2.6.x will continue to work seamlessly? If so, that would be wonderful. Otherwise, we are still too busyto take that on yet.

'use strict';

const _ = require('lodash'),
  core = require('../../core.js'),
  store = _.clone(require('../../store.js'));

function subscription(options) {
  return new Promise(function (resolve, reject) {
    store.bucket.lookupIn(options.id)
      .get('name')
      .get('code')
      .get('active')
      .get('contact')
      .get('subscription')
      .execute(function (error, res) {
        if (error) {
          reject(error);
        } else {
          resolve({
            cas: res.cas,
            value: {
              id: options.id,
              name: res.content('name'),
              code: res.content('code'),
              active: res.content('active'),
              contact: res.content('contact'),
              subscription: res.content('subscription')
            }
          });
        }
      });
  });
}

async function http(event) {
  try {
    console.log(`subscriber.subscription http invoked:\n${JSON.stringify(event)}`);
    let options = core.mapEvent(event),
      response = await subscription(options);
    return core.response.json.success(200, response);
  } catch (error) {
   console.error(error);
    return core.response.json.fail(500, error);
  }
}

module.exports = {
  http: http
};

Thanks

Jay

Hey @The_Cimmerian,

I don’t have my laptop handy to take a look at the source, and it’s been a while since I’ve worked on the 2.x client but I believe that the client returns an error to indicate that not all your commands succeeded, but still returns results individually. If you modify your code to only call reject when results is empty and err is set, you should be able to call content() on the result still and the SDK will throw an exception indicating the field-specific error if one occurred.

P.S. While the 3.x SDK is similar to the 2.x client, it is not a drop in replacement. Though I should mention that 2.x no longer receives regular updates.

Cheers, Brett

1 Like

I see. Ok, I will rework the error condition callback as you recommended.

Thank you as always.

Jay

@brett19 - I did as you instructed pausing on the error block and inspected the “res” property containing any successfully returned pairs. I am very pleased to confirm you are correct. The data for the remaining properties was contained within.

To my knowledge, I haven’t encountered a scenario in which both the error and success response objects in the callback contained data. It does make sense and I will be on the lookout for other scenarios in which that might be the case. It may be happening more frequently than I had considered.

Anyway, I great big thank you to you, sir!

Regards,

Jay

Now this is resolved, I do have a related, follow up question:

I know I can map these results manually and ignore the keys containing missing values. Before I do that, is there an SDK helper function which does that already?

Second, and separate issue:
It would be really helpful to be able to control the order of the keys in the results. This is essential when binding the results to csv headers.

I hacked a solution to get through a sizable effort to export results from a query to csv by prepending the aliases for each key with a letter in the alphabet. If there is a function or option to return results in a mandated order, that would be really useful.

Thanks!
\

Jay

Hey @The_Cimmerian ,

I’m not sure I fully understand what you are asking for regarding ordering. The fields in a JSON object are arbitrarily ordered and the property order of an Object in Javascript is also arbitrary. The ordering that results are returned from a lookupIn operation matches the order you request them in. The best way to order the keys for CSV output is to explicitly write the individual fields, or you can additionally do something like:

const orderedKeys = Object.keys(someObject).sort()
const orderedKeyValuePairs = orderedKeys.map((key) => [key, someObject[key]])

With regards to the fact that err and results are both returned, as well as the ability to automatically map the requested fields into a structured object mirroring the original object, both of these things were resolved in the 3.x SDK. Additionally, I believe lookupIn is the only instance in the Node.js SDK where both an error and results were both being returned.

Cheers, Brett

Excellent.

I appreciate you.

Jay