Problem with N1QL and big attribute

n1ql

#1

Hello!.

I’m having an extrange issue with the java couchbase client. I’m launching a n1ql query that should return 2 rows, if i launch it from the couchbase query editor it returns 2 rows, if i launch it from my app (spring-boot and couchbase sdk) it returns 1 row.
When i set a breakpoint after the query execution and before my query method finish, it returns 2 rows and no exceptions.
It seems the the problem comes with a big attribute storing html, if i remove it from the query it works ok.

The method where i run the query is:

public N1QLExecutionResultDTO executeQuery(CouchbaseConnection ccon, JsonQueryVO jsonQueryVO, DatabaseConnection databaseConnection) {
		N1QLExecutionResultDTO returnValue = new N1QLExecutionResultDTO();

		N1qlParams ryow = N1qlParams.build().consistency(ScanConsistency.REQUEST_PLUS).serverSideTimeout(TIMEOUT_MINUTES, TimeUnit.MINUTES);

		ccon.getBucket().async()
			.query(N1qlQuery.simple(jsonQueryVO.getQuery(), ryow))
			.timeout(TIMEOUT_MINUTES, TimeUnit.MINUTES)
			.toBlocking()
			.subscribe(result -> {
				result.errors()
					.subscribe(
							e -> 
							{
								try {
									JsonNode newElement = mapper.createObjectNode();
									JsonNode error = new ObjectMapper().readTree(e.toString());
									((ObjectNode)newElement).set("error", error);
									returnValue.addError(newElement);
								} catch (IOException e1) {
									LOGGER.error(e1.getMessage());
								}
								
							}
							);
				result.rows()
					.map(row -> row.value())
					.subscribe(
							rowContent -> 
							{
								JsonNode newElement = mapper.createObjectNode();
								
								JsonNode element = null;
								try {
									element =  new ObjectMapper().readTree(rowContent.toString());
								} catch (IOException e1) {
									LOGGER.error(e1.getMessage());
								}

								if(element != null) {
									if(rowContent.getString("id") != null) {
										((ObjectNode)newElement).set("document", element);
									} else {
										newElement = element;
									}
								}
								returnValue.addDocument(newElement);
							},
							runtimeError -> 
							{
								LOGGER.error(runtimeError.getMessage());
							});
				result.info().subscribe(info -> {
					try {
						returnValue.setInfo(new ObjectMapper().readTree(info.asJsonObject().toString()));
					} catch (IOException e1) {
						LOGGER.error(e1.getMessage());
					}
				});
			}
		);
		return returnValue;
	}

The place where i set the breakpoint is in the return returnValue line.

The server is a couchbase Enterprise Edition 5.0.0 build 3519 cluster, with 4 servers and two index servers.

I’m running with java 8.

Thanks!!!


#2

I’m trying to launch the query with this code and it works well

		ccon.getBucket().async()
		.query(N1qlQuery.simple(jsonQueryVO.getQuery(), ryow))
		.flatMap(result ->
        	result.errors()
        		.flatMap(e -> {
        			try {
						JsonNode newElement = mapper.createObjectNode();
						JsonNode error = new ObjectMapper().readTree(e.toString());
						((ObjectNode)newElement).set("error", error);
						returnValue.addError(newElement);
					} catch (Exception e1) {
						LOGGER.error(e1.getMessage());
					}
        			return Observable.<AsyncN1qlQueryRow>empty();
        		})
        		.switchIfEmpty(result.rows())
		)	
		.timeout(TIMEOUT_MINUTES, TimeUnit.MINUTES)
		.map(AsyncN1qlQueryRow::value)
		.toBlocking()
		.subscribe(
		        rowContent -> {
						JsonNode newElement = mapper.createObjectNode();
						JsonNode element = null;
						try {
							element =  new ObjectMapper().readTree(rowContent.toString());
						} catch (IOException e1) {
							LOGGER.error(e1.getMessage());
						}

						if(element != null) {
							if(rowContent.getString("id") != null) {
								((ObjectNode)newElement).set("document", element);
							} else {
								newElement = element;
							}
						}
						returnValue.addDocument(newElement);
		        },
		        runtimeError -> LOGGER.error(runtimeError.getMessage())
		);

The problem is that i’m loosing the info data and i need it.

In the first example i’m subscribing to three observables, is this possible?

Best regards!


#3

Using this example i solve the problem.

This is the query code working

ccon.getBucket()
			.async()
			.query(N1qlQuery.simple(jsonQueryVO.getQuery(), ryow))
			.doOnNext(res -> res.info().forEach(t -> {
				try {
					returnValue.setInfo(new ObjectMapper().readTree(t.asJsonObject().toString()));
				} catch (Exception e1) {
					LOGGER.error(e1.getMessage());
				}
			}))
			.flatMap(result ->
        		result.errors()
        			.flatMap(e -> {
        				try {
        					JsonNode newElement = mapper.createObjectNode();
        					JsonNode error = new ObjectMapper().readTree(e.toString());
        					((ObjectNode)newElement).set("error", error);
        					returnValue.addError(newElement);
        				} catch (Exception e1) {
        					LOGGER.error(e1.getMessage());
        				}
        				return Observable.<AsyncN1qlQueryRow>empty();
        			})
        			.switchIfEmpty(result.rows())
					)
			.timeout(TIMEOUT_MINUTES, TimeUnit.MINUTES)
			.map(AsyncN1qlQueryRow::value)
			.toBlocking()
			.subscribe(
					rowContent -> {
						JsonNode newElement = mapper.createObjectNode();
						JsonNode element = null;
						try {
							element =  new ObjectMapper().readTree(rowContent.toString());
						} catch (IOException e1) {
							LOGGER.error(e1.getMessage());
						}

						if(element != null) {
							if(rowContent.getString("id") != null) {
								((ObjectNode)newElement).set("document", element);
							} else {
								newElement = element;
							}
						}
						returnValue.addDocument(newElement);
					},
					runtimeError -> LOGGER.error(runtimeError.getMessage())
					);

I still have the doubt if the code in the first post is correct and why it isn’t working.

Regards!