Update field in array of objects in json postgres - postgresql

I have postgres database with next json in my table
{"jobTitle":"Technical Writer","distance":60,"skills":[{"name":"Bootstrap (Front-End Framework)","isPrimary":true,"type":""}, {"name":"Javascript","isPrimary":false,"type":""}]}
I need to update field "skills" depends on "isPrimary" value in each item there. If "isPrimary" false, update to 1, otherwise to 5.
I have next query
UPDATE t
SET body = jsonb_set(body::jsonb, '{skills}', s.skills_updated::jsonb)
FROM (
SELECT
jsonb_agg(
jsonb_set(skills::jsonb, '{isPrimary}',
CASE
WHEN skills ->> 'isPrimary' = 'true' THEN '5'::jsonb
ELSE '1'::jsonb
END
)
) as skills_updated
FROM t,
json_array_elements(body -> 'skills') as skills
) s;
This query working incorrectly - it's accumulating all skills across all records in table and then setting this whole array in each record. this is my fiddle https://dbfiddle.uk/m28W7tPy
For instance, if I have next three records:
{"jobTitle":"Writer","distance":60, "skills": [{ "isPrimary": "true", "name": "Node.js" },{ "isPrimary": "false", "name": "Python" },{ "isPrimary": "false", "name": "Javascript" }]}
{"jobTitle":"Writer","distance":60, "skills": [{ "isPrimary": "true", "name": "Mysql" },{ "isPrimary": "false", "name": "Nest.js" }]}
{"jobTitle":"Writer","distance":60, "skills": [{ "isPrimary": "true", "name": "Postgres" },{ "isPrimary": "false", "name": "Typescript" }]}
I want to update just "isPrimary" for all above records and get in result next
{"jobTitle":"Writer","distance":60, "skills": [{ "isPrimary": 5, "name": "Node.js" },{ "isPrimary": 1, "name": "Python" },{ "isPrimary": 1, "name": "Javascript" }]}
{"jobTitle":"Writer","distance":60, "skills": [{ "isPrimary": 5, "name": "Mysql" },{ "isPrimary": 1, "name": "Nest.js" }]}
{"jobTitle":"Writer","distance":60, "skills": [{ "isPrimary": 5, "name": "Postgres" },{ "isPrimary": 1, "name": "Typescript" }]}
when I'm getting after running my query
{"jobTitle":"Writer","distance":60, "skills": [{ "isPrimary": 5, "name": "Node.js" },{ "isPrimary": 1, "name": "Python" },{ "isPrimary": 1, "name": "Javascript" }, { "isPrimary": 5, "name": "Mysql" },{ "isPrimary": 1, "name": "Nest.js" }, { "isPrimary": 5, "name": "Postgres" },{ "isPrimary": 1, "name": "Typescript" }]}
{"jobTitle":"Writer","distance":60, "skills": [{ "isPrimary": 5, "name": "Node.js" },{ "isPrimary": 1, "name": "Python" },{ "isPrimary": 1, "name": "Javascript" }, { "isPrimary": 5, "name": "Mysql" },{ "isPrimary": 1, "name": "Nest.js" }, { "isPrimary": 5, "name": "Postgres" },{ "isPrimary": 1, "name": "Typescript" }]}
{"jobTitle":"Writer","distance":60, "skills": [{ "isPrimary": 5, "name": "Node.js" },{ "isPrimary": 1, "name": "Python" },{ "isPrimary": 1, "name": "Javascript" }, { "isPrimary": 5, "name": "Mysql" },{ "isPrimary": 1, "name": "Nest.js" }, { "isPrimary": 5, "name": "Postgres" },{ "isPrimary": 1, "name": "Typescript" }]}
Can anyone help?

The issue with your query is that you're not keeping trace of each "id" value, nor you're matching it inside the update statement. Adding the "id" selection inside the subquery, and the final WHERE condition to the UPDATE statement, can solve your problem.
UPDATE t
SET body = jsonb_set(body::jsonb, '{skills}', s.skills_updated::jsonb)
FROM (
SELECT id,
jsonb_agg(
jsonb_set(skills::jsonb, '{isPrimary}',
CASE
WHEN skills ->> 'isPrimary' = 'true' THEN '5'::jsonb
ELSE '1'::jsonb
END
)
) as skills_updated
FROM t,
json_array_elements(body -> 'skills') as skills
GROUP BY id
) s
WHERE t.id = s.id ;
Check the demo here.

Related

Postgres Delete item from multiple level Jsonb

The bounty expires in 3 days. Answers to this question are eligible for a +50 reputation bounty.
Ranjith V wants to draw more attention to this question.
I have the following object saved in a jsonb column in Postgres db.
{
"method": "method",
"drive": [
{
"name": "C_Drive",
"key": [
{
"is_active": true,
"created_at": "2023-01-01T00:00:00",
"id": 3,
"value": "value3"
},
{
"is_active": false,
"created_at": "2022-12-01T00:00:00",
"id": 2,
"value": "value2"
},
{
"is_active": false,
"created_at": "2022-11-01T00:00:00",
"id": 1,
"value": "value1"
}]
},
{
"name": "D_Drive",
"key": [
{
"is_active": true,
"created_at": "2023-01-01T00:00:00",
"id": 4,
"value": "value4"
}
}]
}
I want to delete a particular key inside the drive. Say I want to delete key with "id" = 3. How do i do it?

Need help to create a Jolt specification

Need help with a JOLT specification for converting the JSON from the shared input format to the expected format.
[
{
"Header": {
"TeamCD": 2
},
"Player": [
{
"PlayerNumber": 1,
"ShortName": "John",
"UniformNO": 11,
"SmartStart": 20200201,
"SmartEnd": 99999999
},
{
"PlayerNumber": 2,
"ShortName": "James",
"UniformNO": 12,
"SmartStart": 20200201,
"SmartEnd": 99999999
}
]
}
]
Desired output:
[
{
"Field": "TeamCD",
"Type": "20"
"Value": 2,
"Vendor": "Vendor1"
},
{
"Field": "PlayerNumber",
"Type": "23"
"Value": 1,
"Vendor": "Vendor1"
},
{
"Field": "ShortName",
"Type": "24"
"Value": "John",
"Vendor": "Vendor1"
},
{
"Field": "PlayerNumber",
"Type": "23"
"Value": 2,
"Vendor": "Vendor1"
},
{
"Field": "ShortName",
"Type": "24"
"Value": "James",
"Vendor": "Vendor1"
}
]
I am trying to achieve this using JoltTransformJSON now. Is this achievable using JoltTransformJSON? I have it running on Nifi, if not possible with Jolt what are my options?

How to update specific field in mongoDB given conditions?

Given the following mongdoDB structure, how can i update the field isAvailable to false given that the shopName is "jamrt" and slug is "67626dae-1537-40d8-837d-483e5759ada0". This is my query but it does not work: Shop.find({ shopName: shopName}).update({products: {$elemMatch: {slug: slug}}}, { $set: { isAvailable: req.body.isAvailable} } Thanks!
"shopName": "jmart",
"products": [{
"id": 1,
"name": "Clean and Clear Deep Clean Cleanser 100g",
"slug": "8d1c895c-6911-4fc8-a34c-89c6948233d7",
"price": 4.5,
"discount_price": 0,
"category": "Health and Beauty",
"sale": false,
"subcategory": "personal care",
"color": "black",
"article": "Clean and Clear",
"quantity": 9,
"img": "https://firebasestorage.googleapis.com/v0/b/swifty-products.appspot.com/o/Jmart%2FBeauty%2FClean%20and%20Clear%20Deep%20Clean%20Cleanser%20100g.jpg?alt=media",
"vendor": {
"id": 1,
"name": "Clean and Clear"
},
"ratings": {
"star_ratings": 0,
"votes": 0
},
"isAvailable": true
}, {
"id": 2,
"name": "Colgate Total Pro Breath Health",
"slug": "67626dae-1537-40d8-837d-483e5759ada0",
"price": 4.5,
"discount_price": 0,
"category": "Health and Beauty",
"sale": false,
"subcategory": "personal care",
"color": "black",
"article": "Colgate",
"quantity": 9,
"img": "https://firebasestorage.googleapis.com/v0/b/swifty-products.appspot.com/o/Jmart%2FBeauty%2FColgate%20Total%20Pro%20Breath%20Health.jpg?alt=media",
"vendor": {
"id": 2,
"name": "Colgate"
},
"ratings": {
"star_ratings": 0,
"votes": 0
},
"isAvailable": true
},
]
In your case, you are trying to update only the matching sub documents.
The $elemMatch operator while using in projection updates only the first matching sub document.
The $elemMatch operator while using in find updates all the fields of the matching document.
This solution might help you.
With your case, the solution might be the below in mongodb query:
db.Shop.update({"shopName":"jmart","products.slug":"67626dae-1537-40d8-837d-483e5759ada0"}, {$set: {“products.$[i].isAvailable”: false}}, {arrayFilters: [{“i.slug”: "67626dae-1537-40d8-837d-483e5759ada0"}]})

How to update a part of an array sub document in MongoDB

I have this document in my mongodb collection:
{
"_id": "YLRM9Wi7f6tp6qNbS",
"sessionId": "hLDkkJKR4Muik6tbe",
"userId": "ZYoG4cH8HcCDPMDGr",
"shopId": "J8Bhq3uTtdgwZx3rz",
"workflow": {
"status": "",
"workflow": ["String"]
},
"billing": [Object],
"discount": 0,
"tax": 0,
"items": [
{
"_id": "JwR233jD2c4HKeYKq",
"shopId": "J8Bhq3uTtdgwZx3rz",
"productId": "BCTMZ6HTxFSppJESk",
"quantity": 1,
"product": {
"_id": "BCTMZ6HTxFSppJESk",
"title": "Product",
"shopId": "J8Bhq3uTtdgwZx3rz",
"ancestors": [],
"createdAt": "2018-01-12T10:22:18.853Z",
"description": "",
"handle": "product",
"hashtags": [
"rpjCvTBGjhBi2xdro",
"cseCBSSrJ3t8HQSNP"
],
"price": {
"range": "12.99 - 19.99",
"min": 12.99,
"max": 19.99
},
"isVisible": true,
"isLowQuantity": false,
"isSoldOut": false,
"isBackorder": false,
"metafields": [
{
"key": "Material",
"value": "Cotton"
},
{
"key": "Quality",
"value": "Excellent"
}
],
"pageTitle": "",
"type": "simple",
"updatedAt": "2018-01-12T10:22:18.854Z",
"vendor": "Vendor_Name",
"originCountry": "country",
"requiresShipping": true,
"isDeleted": false,
"template": "productDetailSimple",
"workflow": {
"status": "new"
}
},
"variants": {},
"title": "Product",
"type": "simple",
"parcel": {
"weight": 25,
"height": 3,
"width": 10,
"length": 10
},
"shippingMethod": {
"shopId": "J8Bhq3uTtdgwZx3rz",
"shipmentQuotes": [Object],
"shipmentQuotesQueryStatus": {
"requestStatus": "success",
"numOfShippingMethodsFound": 11
},
"_id": "s3EJXrLsZe73RbLiD",
"address": {},
"shipmentMethod": {},
"paymentId": "nyybR5BNvDDrJrtwe",
"items": [
{
"_id": "JwR233jD2c4HKeYKq",
"productId": "BCTMZ6HTxFSppJESk",
"shopId": "J8Bhq3uTtdgwZx3rz",
"variantId": "CJoRBm9vRrorc9mxZ"
}
],
"workflow": {
"status": "new",
"workflow": ["String"]
}
},
"workflow": {
"status": "new",
"workflow": ["String"]
}
}
],
"shipping": [Object],
"email": "johndoe#mail.com",
"cartId": "L6sSGv4NR9rpbDbsd",
"createdAt": "2018-01-12T10:22:18.850Z"
}
The field items is an array of objects, I would like to update just a part of the object specifically the workflow field without touching other part of the objects in items array.
I was able to do this using a loop, but it caused some tests to fail. Is there a better of doing this with using a loop?
Thank you.
You can try findAndModify method.
Traverse to the workflow key ad try to set the value.
Hope this would help.

update or replace the mongoose nested array object

I have a timesheet schema which results as below and I want to replace single data array object by a new set of values in mongoose. Either i want remove already existing object and push a new set of values or update the old object with new values.Please suggest me a proper way to achieve this. I am was struggled a lot to do this, because i am new to mongoose and mongodb. Thanks in advance
{
"_id": ObjectId("53f1fb3401ea96440d62646b"),
"user_id": "andrew",
"type": "Solutions",
"timesheets": [{
"weekStartDate": ISODate("2014-08-18T00:00:00Z"),
"weekEndDate": ISODate("2014-08-22T00:00:00Z"),
"_id": ObjectId("53f1fb3401ea96440d62646c"),
"data": [{
"date": ISODate("2014-08-18T00:00:00Z"),
"_id": ObjectId("53f1fb3401ea96440d62646d"),
"record": [{
"_id": ObjectId("53f1fb3401ea96440d626470"),
"desc": "",
"cellId": "0:0",
"custName": "Coach",
"custID": "2",
"timeSpend": "04:00",
"categoryName": "Billing",
"categoryID": "1"
}, {
"_id": ObjectId("53f1fb3401ea96440d62646f"),
"desc": "Description",
"cellId": "0:1",
"custName": "",
"custID": "",
"timeSpend": "05:00",
"categoryName": "Solution",
"categoryID": "4"
}, {
"_id": ObjectId("53f1fb3401ea96440d62646e"),
"desc": "Description",
"cellId": "0:2",
"custName": "",
"custID": "",
"timeSpend": "06:00",
"categoryName": "GTM",
"categoryID": "3"
}],
"savedFlag": false,
"submitFlag": false
}, {
"date": ISODate("2014-08-19T00:00:00Z"),
"_id": ObjectId("53f1fb4e01ea96440d626471"),
"record": [{
"_id": ObjectId("53f1fb4e01ea96440d626474"),
"desc": "",
"cellId": "1:0",
"custName": "Morgan",
"custID": "3",
"timeSpend": "04:00",
"categoryName": "RFP",
"categoryID": "2"
}, {
"_id": ObjectId("53f1fb4e01ea96440d626473"),
"desc": "",
"cellId": "1:1",
"custName": "Morgan",
"custID": "3",
"timeSpend": "05:00",
"categoryName": "RFP",
"categoryID": "2"
}, {
"_id": ObjectId("53f1fb4e01ea96440d626472"),
"desc": "",
"cellId": "1:2",
"custName": "Citi",
"custID": "1",
"timeSpend": "04:00",
"categoryName": "Sales",
"categoryID": "0"
}],
"savedFlag": false,
"submitFlag": false
}],
"savedFlag": true,
"submitFlag": false
}],
"__v": 0
} >