Iterating Object of Array in Couchbase - arrays

How to iterate Object of Array to get specific key value pair from JSON object. I am using Couchbase Server. Please suggest N1QL for Couchbase.
Below is my JSON format
{
"A":{
"B":{
"C": {
"D":[
{
"attr":[
{
"Name" : "abc"
}
],
"Name" : "outer"
}
], ​
"E":[
{
"attr":[
{
"Name" : "xyz"
}
],
"Name" : "outer1"
}
​]
}
}
}
}
​
Want to retrieve value for Name attribute inside each array of object C. Please note there are two fields with same name inside Array , so want to just access outer one. Key value pair inside C is dynamic.
Thanks in Advance!

If you really looking for all the names objects of path A.B.C
use the following expression
ARRAY v.Name FOR v WITHIN A.B.C WHEN v.Name IS NOT MISSING END
SELECT ARRAY v.Name
FOR v WITHIN d.A.B.C
WHEN v.Name IS NOT MISSING
END AS val
FROM [{ "A":{ "B":{ "C": { "D":[{"Name" : "test1", "state" : "state1"} ],
"E":[{"Name" : "test2", "state" : "state2"} ],
"F":[{"Name" : "test2", "state" : "state2"} ]
}
}
}
}
] AS d;
{
"val": [
"test1",
"test2",
"test2"
]
}
If you need to pick only some you need to have some other field present in that object consistently.
ARRAY v.Name FOR v WITHIN A.B.C WHEN v.Name IS NOT MISSING AND v.attr IS NOT MISSING END
SELECT ARRAY v.Name FOR v WITHIN d.A.B.C WHEN v.Name IS NOT MISSING AND v.attr IS NOT MISSING END
FROM [{ "A":{ "B":{ "C": { "D":[ { "attr":[ { "Name" : "abc" } ], "Name" : "outer" } ], "E":[ { "attr":[ { "Name" : "xyz" } ], "Name" : "outer1" } ] } } } }] AS d;
If you already know the predefined path (don't use recursive).
Construct ARRAY of the values of the dynamic field object. As the value is already ARRAY flatten by 1 level, Then iterate over ARRAY and get Name. If you need unique use ARRAY_DISTINCT()
ARRAY v.Name FOR v IN ARRAY_FLATTEN((ARRAY nv FOR n:nv IN d.A.B.C END),1) END
SELECT ARRAY v.Name FOR v IN ARRAY_FLATTEN((ARRAY nv FOR n:nv IN d.A.B.C END),1) END AS obj
FROM [{ "A":{ "B":{ "C": { "D":[ { "attr":[ { "Name" : "abc" } ], "Name" : "outer" } ], "E":[ { "attr":[ { "Name" : "xyz" } ], "Name" : "outer1" } ] } } } }] AS d;

Related

Update nested array in a mongo document

I have below collection
{
"_id" : ObjectId("5d7e6c54c23c210001108556"),
“parentId" : "5d0162ba69cf130001a16115",
"tasks" : [
{
"_id" : "ae60a8f1",
"taskMetaDataIds” : [
ObjectId("5d55a648e2f7320001e578ac")
],
"name" : “meta 3"
},
{
"_id" : "07544d96",
"taskMetaDataIds" : [
ObjectId("5d55a648e2f732676676676”),
ObjectId("5d55a648e2612333556888”)
],
"name" : “meta 2"
},
],
"name" : “New Topic",
"createdBy" : "01526151-8303-450f-b08b-b36a1760b774",
"createdDate" : ISODate("2019-09-15T16:52:36.150+0000"),
"updatedDate" : ISODate("2019-09-15T16:52:36.150+0000")
}
I am looking for below output . Is there an operator which can directly convert the array of objects into array of strings as shown below. I can do it with a script by looping over the taskMetaDataIds array but I am looking to use a direct mongo operator which suits my purpose.
{
"_id" : ObjectId("5d7e6c54c23c210001108556"),
“parentId" : "5d0162ba69cf130001a16115",
"tasks" : [
{
"_id" : "ae60a8f1",
"taskMetaDataIds” : [
"5d55a648e2f7320001e578ac"
],
"name" : “meta 3"
},
{
"_id" : "07544d96",
"taskMetaDataIds" : [
"5d55a648e2f732676676676”,
“5d55a648e2612333556888”
],
"name" : “meta 2"
},
],
"name" : “New Topic",
"createdBy" : "01526151-8303-450f-b08b-b36a1760b774",
"createdDate" : ISODate("2019-09-15T16:52:36.150+0000"),
"updatedDate" : ISODate("2019-09-15T16:52:36.150+0000")
}
I tried below but it does not seem to be working-
db.getCollection("data").updateOne({"_id":ObjectId("5d7e6c54c23c210001108556")}, [{ $set: { "tasks.taskMetaDataIds": "$tasks.taskMetaDataIds.str" } }])
$set - Set tasks array field.
1.1. $map - Iterate each element in the tasks array and return a new array.
1.1.1. $mergeObjects - Merge the current iterated task object and taskMetaDataIds array (from the result 1.1.1.1).
1.1.1.1. $map - Iterate the current iterated task object's taskMetaDataIds array and returns a new array.
1.1.1.1.1. $toString - Convert each iterate id from ObjectId type to string type.
db.getCollection("data").updateOne({
"_id": ObjectId("5d7e6c54c23c210001108556")
},
[
{
$set: {
"tasks": {
$map: {
input: "$tasks",
as: "task",
in: {
$mergeObjects: [
"$$task",
{
"taskMetaDataIds": {
$map: {
input: "$$task.taskMetaDataIds",
in: {
$toString: "$$this"
}
}
}
}
]
}
}
}
}
}
])
Demo # Mongo Playground

Mongodb - Find in deeply nested array

I am trying to find if type=conv is present in given rs , which is present in d --> ds --> rs --> type.
DOCUMENT
{
"_id" : ObjectId("5ec25873bd796ff191e695b1"),
"c_name" : "c1",
"t_name" : "t1",
"d" : [
{
"name" : "d1",
"ds" : [
{
"name" : "ds1",
"rs" : [
{
"type" : "conv"
}
]
}
]
},
{
"name" : "d2",
"ds" : [
{
"name" : "ds2",
"rs" : []
}
]
}
]
}
QUERY:
filter = {
"$and": [
{"c_name": {'$eq': 'c1'}},
{"t_name": {'$eq': 't1'}},
{"d.name": {'$eq': 'd2'}},
{"d.ds.name": {'$eq': 'ds2'}},
{"d.ds.rs.type": {'$eq': 'conv'}}
]
}
OUTPUT
It is returning me document, i guess it is looking for presence of type = conv in full document, even though it is not present on ds2 ( part of d2), but present on ds1 ( part of d1).
Do we have simpler way to find if it exists or not, I would like to first find and then using array filters , we can update the specific element inside deeply nested array.
Could someone please suggest how should I approach this problem? ( if we have any solution without using aggregation )
You need to use $elemMatch for these type of condition, And you can match strings without $eq operator
filter = {"$and": [
{"c_name": "c1"},
{"t_name": "t1"},
{ "d": { $elemMatch: { "name": "d2", "ds.name": "ds2" , "ds.rs.type": "conv"} } }
]}
With $elemMatch It will search only in the array where all condition will be true
Thanks #puneet , i need to try above. However, i am using now this
filter_query = {
"$and": [
{"c_name": {'$eq': 'c1'}},
{"t_name": {'$eq': 't1'}},
{
'd': {
'$elemMatch': {
'name': 'd2',
'ds': {
'$elemMatch':
{'name': 'ds2',
'rs':
{'$elemMatch':
{
"type": 'conv'}
}
}
}
}
}
}]}
This is also working !!

How to remove elements from array of an embedded document which are not in my array

This is my document.
{
"group_name" : "Test Group 6 (Edit)",
"created_on" : "1464367826787",
"group_id" : "group_14",
"members" : [
{
"user_id" : "user_7",
"added_on" : "1464367826787"
}
],
"is_deleted" : 0
}
I'm having list of user_ids and I need to remove user_ids which are not in the list of user_ids I have. How to remove "user_50" if input list = ["user_7"] ?
You need to use the $nin operator to select your documents, the updateMany method if you want to update multiple documents or updateOne method to update a single document.
db.users.updateMany(
{},
{ "$pull": { "members": { "user_id": { "$nin": [ "user_7" ] } } }}
)
db.users.update(
{},
{$pull:
{members:{'user_id':{$ne:"user_7"}}}}, {multi:true})

MongoDB: Find all matched array element from single document

I have a mongodb document like this,
{
"_id" : ObjectId("4e8ae86d08101908e1000001"),
"eId": 101,
"about": "test",
"tags" : [
{"name": "jana"},
{"name":"bala"},
{"name":"jk"},
{"name":"charles"}
]
}
I need to find all matched array elements, where the name matched with given array.
db.coll.find({"tags": {"$elemMatch": {"name": {"$in": [/^jana/i, /^charles/i] }}}})
for this query i got the following result
{
"_id" : ObjectId("4e8ae86d08101908e1000001"),
"tags" : [
{
"name" : "jana"
}
]
}
$elemMatch query only return the first matched element, but i want all the matched array element like this,
{
"_id" : ObjectId("4e8ae86d08101908e1000001"),
"tags" : [
{
"name" : "jana"
},
{
"name" : "charles"
}
]
}
Is it possible to get the result like this?
note: i don't want any others fields, I want only the matched array elements along with _id
You can use MongoDB Aggregation Pipeline:
db.coll.aggregate([
{'$unwind': '$tags'},
{'$match':
{"tags.name":
{"$in": [/^jana/, /^charles/i] }
}
},
{'$group':
{
'_id': '$_id',
'tags':
{'$push': '$tags'}
}
}
])
Result : -
{
"result" : [
{
"_id" : ObjectId("5538b214706a90c718f75a41"),
"tags" : [
{
"name" : "jana"
},
{
"name" : "charles"
}
]
}
],
"ok" : 1
}

MongoDB Update Array element

I have a document structure like
{
"_id" : ObjectId("52263922f5ebf05115bf550e"),
"Fields" : [
{
"Field" : "Lot No",
"Rules" : [ ]
},
{
"Field" : "RMA No",
"Rules" : [ ]
}
]
}
I have tried to update by using the following code to push into the Rules Array which will hold objects.
db.test.update({
"Fields.Field":{$in:["Lot No"]}
}, {
$addToSet: {
"Fields.Field.$.Rules": {
"item_name": "my_item_two",
"price": 1
}
}
}, false, true);
But I get the following error:
can't append to array using string field name [Field]
How do I do the update?
You gone too deep with that wildcard $. You match for an item in the Fields array, so you get a access on that, with: Fields.$. This expression returns the first match in your Fields array, so you reach its fields by Fields.$.Field or Fields.$.Result.
Now, lets update the update:
db.test.update({
"Fields.Field": "Lot No"
}, {
$addToSet: {
"Fields.$.Rules": {
'item_name': "my_item_two",
'price':1
}
}
}, false, true);
Please note that I've shortened the query as it is equal to your expression.

Resources