Get data from view via key fail

Hi, folks:
after i upgrade libcouchbase to latest one, following code doesn’t work.
I try to get data from view via number key. lcb_connect success but lcb_make_http_request failed. Any clue why?

lcb_error_t err;
lcb_http_request_t req;
lcb_http_cmd_t cmd;
	std::stringstream key_ss;
	key_ss << _key;
	string uri = "_design/"+_designdocname + "/_view/" + _viewname +"?key=" + key_ss.str();

	std::cout<<"uri:"<<uri<<std::endl;
	size_t nbytes = 0;
	const char * bytes = NULL;
    if (bytes) {
        nbytes = strlen(bytes);
    }
	cmd.version = 0;
    cmd.v.v0.path = uri.c_str();
    cmd.v.v0.npath = strlen(uri.c_str());
    cmd.v.v0.body = bytes;
    cmd.v.v0.nbody = nbytes;
    cmd.v.v0.method = nbytes > 0 ? LCB_HTTP_METHOD_POST : LCB_HTTP_METHOD_GET;
    cmd.v.v0.chunked = 1;
    cmd.v.v0.content_type = "application/json";
	err = lcb_make_http_request(instance, NULL, LCB_HTTP_TYPE_VIEW, &cmd, &req);

	if (err != LCB_SUCCESS) {
        fprintf(stderr, "Failed to get view by key: %s\n", lcb_strerror(NULL, err));
        return false;
    }
	lcb_wait(instance);
	_response = outResponse;
	return true;

How exactly is this failing? What version were oyu using previously?

Bear in mind that as of version 2.4.7, the C library has a proper view API: http://docs.couchbase.com/sdk-api/couchbase-c-client-2.5.0/group__lcb-view-api.html, http://docs.couchbase.com/developer/c-2.4/view-queries.html

the fail message asking me to check if connection is created or not, but lcb_connect did return success.
i’m using version 2.5
about view API lcb_view_query,can we specify key in parameter lcb_CMDVIEWQUERY *cmd ?
from doc http://docs.couchbase.com/sdk-api/couchbase-c-client-2.5.0/group__lcb-view-api.html#structlcb___c_m_d_v_i_e_w_q_u_e_r_y
looks like we can specify key in postdata, but what’s the format? it’s key=abc or just value of key?
could you give me sample code?

thanks a lot!
Jiayan

You must call lcb_wait() after lcb_connect() (this should be the case for older versions as well)

You would use the optstr/noptstr to add any additional view parameter information (as you are doing with path in the HTTP subsystem, except that you wouldn’t need to use _view/name/_design/name?)

i did call lcb_wait() after lcb_connect() like we did in older version.

so can i use optstr this way?
optstr = “key=” + keyss.str();

thanks,

Yeah. Just like that. Let me try to run your example and see if I spot anything…

Can you also verify the connection to the cluster succeeded? e.g. lcb_get_bootstrap_status() right after lcb_connect(instance);lcb_wait(instance);

thanks a lot.
I didn’t know we need to call lcb_get_bootstrap_status after lcb_connect(instance);lcb_wait(instance);
in older version, we call lcb_set_error_callback(instance, error_callback); before lcb_connect then i got compile error, so i switch to lcb_set_bootstrap_callback(instance, error_callback);
here is my CouchbaseHandler looks like, any comments would be appreciated.

bool CouchbaseHandler::init(const string _host,const string _port,const string _user,const string _password,const string _bucket)
{
	host = _host;
	port = _port;
	user = _user;
	password = _password;
    bucket = _bucket;
    outKey = "";
    outValue = "";
	string complete_host = host +":"+port;
	std::cout<<"Init libcouchbase instance,hots: "<<complete_host<<",user: "<<user<<",pass: "<<password<<" ,bucket: "<<bucket<<std::endl;
	lcb_error_t err;
	memset(&create_options, 0, sizeof(create_options));
	create_options.version = 3;
	std::string connectStr = "couchbase://"+host+"/"+bucket;
	create_options.v.v3.connstr = connectStr.c_str();
    create_options.v.v3.passwd = password.c_str();

    err = lcb_create(&instance, &create_options);
    if (err != LCB_SUCCESS) 
    {
        // fprintf(stderr, "Failed to create libcouchbase instance: %s\n",lcb_strerror(NULL, err));
		std::cout<<"Failed to create libcouchbase instance,hots: "<<host<<",user: "<<user<<",pass: "<<password<<" ,bucket: "<<bucket<<std::endl;
        return false;
    }
    /* Set up the handler to catch all errors! */
    //lcb_set_error_callback(instance, error_callback);
    lcb_set_bootstrap_callback(instance, error_callback);

    /*
     * Initiate the connect sequence in libcouchbase
     */
    if ((err = lcb_connect(instance)) != LCB_SUCCESS) 
    {
        // fprintf(stderr, "Failed to initiate connect: %s\n",lcb_strerror(NULL, err));
		std::cout<<"Failed to connect to libcouchbase instance,hots: "<<host<<",user: "<<user<<",pass: "<<password<<" ,bucket: "<<bucket<<std::endl;
        return false;
    }
    /* Run the event loop and wait until we've connected */
    lcb_wait(instance);

    //set up callback for store requests
    lcb_set_store_callback(instance, store_callback);

    
    //Set up a callback for our get requests
    lcb_set_get_callback(instance, get_callback);
	lcb_set_http_complete_callback(instance, complete_callback); 
	//Set up data call back for view request 
	lcb_set_http_data_callback(instance, data_callback);
	//std::cout<<"init return true"<<std::endl;
	
	lcb_set_remove_callback (instance, remove_callback);
    return true;
}

It looks mainly OK. I will note that lcb_set_bootstrap_callback is really only useful if you are dealing with an event loop and you want to be notified of connection errors asynchronously.

If your application is blocking, the following would be much simpler to read:

if ((err = lcb_connect(instance)) != LCB_SUCCESS) {
  // print error and exit
}
lcb_wait(instance);
if ((err = lcb_get_bootstrap_status(instance)) != LCB_SUCCESS) {
  // print error and exit
}
// ....

lcb_connect actually fail
error_callback: Authentication failed. You may have provided an invalid username/password combination

i’m pretty sure the password is correct, but looks like we don’t need username in version 2.5?
anything wrong in following code ?

create_options.version = 3;
std::string connectStr = “couchbase://”+host+"/"+bucket;
create_options.v.v3.connstr = connectStr.c_str();
create_options.v.v3.passwd = password.c_str();

err = lcb_create(&instance, &create_options);
if (err != LCB_SUCCESS) 
{
    // fprintf(stderr, "Failed to create libcouchbase instance: %s\n",lcb_strerror(NULL, err));
	std::cout<<"Failed to create libcouchbase instance,hots: "<<host<<",user: "<<user<<",pass: "<<password<<" ,bucket: "<<bucket<<std::endl;
    return false;
}
/* Set up the handler to catch all errors! */
//lcb_set_error_callback(instance, error_callback);
lcb_set_bootstrap_callback(instance, error_callback);

/*
 * Initiate the connect sequence in libcouchbase
 */
if ((err = lcb_connect(instance)) != LCB_SUCCESS) 
{
    // fprintf(stderr, "Failed to initiate connect: %s\n",lcb_strerror(NULL, err));
	std::cout<<"Failed to connect to libcouchbase instance,hots: "<<host<<",user: "<<user<<",pass: "<<password<<" ,bucket: "<<bucket<<std::endl;
    return false;
}
/* Run the event loop and wait until we've connected */
lcb_wait(instance);
if ((err = lcb_get_bootstrap_status(instance)) != LCB_SUCCESS) {
   // print error and exit
   std::cout<<"connect fail"<<std::endl;
}

I’d be more interested in seeing log output. See http://docs.couchbase.com/developer/c-2.4/logging.html

thanks, i can get data in row callback. One more question, what if the key map to multiple rows?
so the row_callback would be called multiple times? if it’s called multiple times, how can I aggregate data from multiple row callnback? thanks in advance.

You can use the cookie argument to lcb_view_query. The response will also have a cookie field which is the same pointer passed to the view_query function. This cookie is an opaque pointer if your choosing which can be a list, for example, to help you aggregate.