Couchbase N1q1 update array element and return only the updated block - couchbase

I want to update an element in an array object and return only the few elements from the updated array object.
Document:
{
"doctype" : "report",
"name":"nick",
"emailId":"nick123#gmail.com",
"subjects" : [{
"name":"SOA",
"tutor":"roshan",
"classes" : "12",
"mark" : 40,
"subid": "5678"
},
{
"name":"UNIX",
"tutor":"mathew",
"classes" : "9"
"mark" : 50,
"subid" : "3788"
}
],
"id" : "12345"
}
n1q1:
update bucket1
Set i.status = “pass” for i in subjects when i.mark > 40 end
where doctype = "report"
returning *
above query returns the whole document but I want only few element from the updated array object like below. Can you please help me on this . Thanks
Expected query response
{
"id" : "12345",
"subid: “3788”,
"name":"UNIX"
}

Returning clause you can build expression that you want.
You are updating ARRAY, it means it can update more than one element. so you can return as ARRAY, if you want FIRST element replace with ARRAY with FIRST.
UPDATE bucket1 AS b
SET i.status = "pass" FOR i IN b.subjects WHEN i.mark > 40 END
WHERE b.doctype = "report" AND (ANY v IN b.subjects SATISFIES v.mark > 40 END)
RETURNING (ARRAY {v.id, v.subid, v.name} FOR v IN b.subjects WHEN v.mark > 40 END) AS subjects;
You can only return modified info, you will not able to return original info.

Related

Postgresql - Renaming the key of all objects in an array of a JSON column

PostgreSQL 13
The goal is to rename all src keys in the photos array to image.
I have a table plans which has a column json with a simplified structure similar to the below sample.
{
"id": "some id",
"name": "some name",
"tags": [
{
"keyId": 123,
"valueId": 123
},
{
"keyId": 123,
"valueId": 123
}
],
"score": 123,
"photos": [
{
"src": "someString"
},
{
"src": "someString"
}
],
"payment": true
}
The number of objects in the photos array varies, but in general, it is less than 10, so a non-iterating method would be fine, too.
I tried something like this, but it is only good for modifying the value of a key, not the name of the key itself.
UPDATE
plans
SET
json = jsonb_set(json::jsonb, '{photos, 0, src}', '"image"')
;
With the following attempt, I was actually able to rename the key but it overwrites everything else, so only an object with {"image": "someUrl"} is left:
UPDATE
plans
SET
json = (json -> 'photos' ->> 0)::jsonb - 'src' || jsonb_build_object ('image',
json::jsonb -> 'photos' -> 0 -> 'src')
WHERE json::jsonb ? 'photos' = true;
Is there a way to rename keys as expected?
So in the end I used a variation of my initial jsonb_set method. The solution isn't elegant or efficient, but since it is a one-time operation, it was only important to work:
UPDATE
plans
SET
json = jsonb_set(json::jsonb, '{photos, 0, imageUrl}', (json->'photos'->0->'src')::jsonb)
WHERE
json->'photos'->0->'src' IS NOT NULL
;
This query would add the imageUrl key with the existing value of the src key for the first object (position 0) in the photos array. So it left me with src and imageUrl key.
To remove the src key, I ran the following query
UPDATE
plans
SET
json = json::jsonb #- '{ photos, 0, src}'
;
Repeating this as many times as the maximum number of elements in a photos array eventually solved the issue for me.

Groovy: json get value of id based on child value

I have a json as below:
[
{
"id":6619137,
"oid":"6fykq37gm60x",
"key":{
"key":"6619137"
},
"name":"Prod",
"planKey":{
"key":"PDP"
},
"environments":[
{
"id":6225923,
"key":{
"key":"6619137-6225923"
},
"name":"Production",
"deploymentProjectId":6619137,
}
],
},
{
"id":6619138,
"oid":"6fykq37gm60y",
"key":{
"key":"6619138"
},
"name":"QA",
"planKey":{
"key":"QDP"
},
"environments":[
{
"id":6225924,
"key":{
"key":"6619138-6225924"
},
"name":"QA",
"deploymentProjectId":6619138,
}
],
},
]
I can use the below code to extract the value of id and environments.id based on the name value. projectID will give 6619137 and environmentID will give 6225923
def e = json.planKey.find{it.name=='Prod'}
def projectID = e.id
def environmentID = e.environments[0].id
However, when I try to extract the value of id and environments.id based on the plankey.key value (e.g. PDP or QDP), using the same format above returns me an error of java.lang.NullPointerException: Cannot get property 'id' on null object at Script60.run(Script60.groovy:52)
def e = json.planKey.find{it.planKey=='{key=PDP}'}
def projectID = e.id
def environmentID = e.environments[0].id
Is there a way I can get the projectID with the plankey key value?
Think of your JSON object as a key/value map with multiple levels. There is no such item as
json.find{it.planKey=='{key=PDP}'}
However, you can find with values at any level, like this:
def e = json.find{it.planKey.key == "PDP"}
If you have a structure where planKey may not exist, or it doesn't always have key, that's a bit different, but from your question it sounds like that's not the case here.
EDIT: correcting syntax based on comment below.

Update nested tag in JSON field in Postgresql

Ihave the following JSON field:
{
"Id": "64848e27-c25d-4f15-99db-b476d868b575",
"Associations_": [
"RatingBlockPinDatum"
],
"RatingScenarioId": "00572f95-9b81-4f7e-a359-3df06b093d4d",
"RatingBlockPinDatum": [
{
"Name": "mappedmean",
"PinId": "I.Assessment",
"Value": "24.388",
"BlockId": "Score"
},
{
"Name": "realmean",
"PinId": "I.Assessment",
"Value": "44.502",
"BlockId": "Score"
}]}
I want to update the Value from 24.388 to a new value in the nested array "RatingBlockPinDatum" where Name = "mappedmean".
Any help would be appreciated. I have already tried this but couldn't adapt it to work properly:
[Update nested key with postgres json field in Rails
You could first get one result per element in the RatingBlockPinDatum JSON array (using jsonb_array_length and generate_series) and then filter that result for where the Name key has the value "mappedmean". Then you have the records that need updating. The update itself can be done with jsonb_set:
with cte as (
select id, generate_series(0, jsonb_array_length(info->'RatingBlockPinDatum')-1) i
from mytable
)
update mytable
set info = jsonb_set(mytable.info,
array['RatingBlockPinDatum', cte.i::varchar, 'Value'],
'"99.999"'::jsonb)
from cte
where mytable.info->'RatingBlockPinDatum'->cte.i->>'Name' = 'mappedmean'
and cte.id = mytable.id;
Replace "99.999" with whatever value you want to store in that Value property.
See it run on rextester.com

How to check a value matches with another correpsonding value in a json response

What is the most dynamic way of checking each instance of a json response value matches another json response value within a script assertion?
What I mean is lets say I have the following response below:
{
"xxx": [{
"roomInformation": [{
"xxx": xxx
}],
"totalPrice": xxx
},
{
"roomInformation": [{
xxx: xxx
}],
"totalPrice": xxx
}
]
}
I want to check that the first room price to match with the first totalPrice and the second roomPrice to match with the second totalPrice. It has to be dynamic as I may get many different instances of this so I can't simply just look through the json with [0] and [1]. Virtually check each roomPrice matches with its corresponding totalPrice.
Thanks
So given the Json as a variable:
def jsonTxt = '''{
"hotels": [{
"roomInformation": [{
"roomPrice": 618.4
}],
"totalPrice": 618.4
},
{
"roomInformation": [{
"roomPrice": 679.79
}],
"totalPrice": 679.79
}
]
}'''
We can then use the following script:
import groovy.json.*
new JsonSlurper().parseText(jsonTxt).hotels.each { hotel ->
assert hotel.roomInformation.roomPrice.sum() == hotel.totalPrice
}
As you can see, I'm using sum to add all the roomInformation.roomPrice values together. In your example, you only have one price, so this will be fine.. And it will also cover the case where you have multiple rooms adding up to make the total
Here is the script assertion to check each roomPrice is matching or not with totalPrice.
EDIT: based on OP's full response provided here
Script Assertion:
//Check if the response is not empty
assert context.response, "Response is empty or null"
def json = new groovy.json.JsonSlurper().parseText(context.response)
def sb = new StringBuffer()
json.regions.each { region ->
region.hotels.each { hotel ->
(hotel?.totalPrice == hotel?.roomInformation[0]?.roomPrice) ?: sb.append("Room price ${hotel?.roomInformation[0]?.roomPrice} is not matching with total price ${hotel.totalPrice}")
}
}
if (sb.toString()) {
throw new Error(sb.toString())
} else { log.info 'Prices match' }

How to display 'c' array values alone from the given JSON document below using MongoDB?

I am a newbie to MongoDB. I am experimenting the various ways of extracting fields from a document inside collection.
Here in the below JSON document, I am finding it difficult to get extract it according to my need
{
"_id":1,
"dependencies":{
"a":[
"hello",
"hi"
],
"b":[
"Hmmm"
],
"c":[
"Vanilla",
"Strawberry",
"Pista"
],
"d":[
"Carrot",
"Cauliflower",
"Potato",
"Cabbage"
]
},
"productid":"25",
"date":"Thu Jul 30 11:36:49 PDT 2015"
}
I need to display the following output:
c:[
"Vanilla",
"Strawberry",
"Pista"
]
Can anyone please help me in solving it?
MongoDB Aggregation comes into rescue to get the result you are looking for :
$Project--> Passes along the documents with only the specified fields to the next stage in the pipeline. The specified fields can be existing fields from the input documents or newly computed fields.
db.collection.aggregate( [
{ $project :
{ c: "$dependencies.c", _id : 0 }
}
]).pretty();
As per the output you required, we just need to project ( display) the field "dependencies.c" , so we are creating a new field "c" and assigining the value of the "dependencies.c" into it.
Also by defalut "_id" field will be display along with the result, since you dont need it, so we are suppressing of the _id field by assigining "_id" : <0 or false>, so that it will not display the _id field in the output.
The above query will fetch you the result as below :
"c" : [
"Vanilla",
"Strawberry",
"Pista"
]