MongoDB: Select from one collection based on another collection - json

I'm new to MongoDB and I'm trying to find a category that meets the required params. I have two collections, categories (list of categories) and ref_categories (manages nested category relationships)
collection categories:
[
{
"id": "A1001",
"key": "3dmodels",
},
{
"id": "A1002",
"key": "animals",
},
{
"id": "A1003",
"key": "birds",
},
{
"id": "A1004",
"key": "reptiles",
},
{
"id": "A1005",
"key": "birds",
}
]
collection categories_ref:
[
{
"category_id": "A1001", // 3dmodels parented to
"p_category_id": "root", // root
},
{
"category_id": "A1002", // animals parented to
"p_category_id": "A1001", // 3dmodels
},
{
"category_id": "A1003", // birds parented to
"p_category_id": "A1002", // animals
},
{
"category_id": "A1004", // reptiles parented to
"p_category_id": "A1002", // animals
},
{
"category_id": "A1005", // birds parented to
"p_category_id": "A1004", // reptiles
}
]
You'll noticed in my Categories collection there are two entries for 'birds' however they each have a different parent category.
I'm trying to create a query that allows me to find the category by key and parent category key.
Pseudo example.... I want to find 'birds' but the entry who has a parent called 'animals'. Otherwise return null.
the expected output would be
// find category_key: "birds" parent_category_key: "animals"
{
"id": "A1003",
"key": "birds",
}

You can use a $lookup with a pipeline where you match two conditions:
Join based on id. Categories id is the same as reference category_id.
Also check p_category_id is the desired code.
And after that you can $match to not get elements where the join result is empty (i.e, keep elements where exists a value).
db.categories.aggregate([
{
"$match": {"key": "birds"}
},
{
"$lookup": {
"from": "categories_ref",
"let": {"id": "$id"},
"pipeline": [
{
"$match": {
"$expr": {
"$and": [
{
"$eq": ["$category_id","$$id"]
},
{
"$eq": ["$p_category_id","A1002"]
}
]
}
}
}
],
"as": "cat_ref"
}
},
{
"$match": {"cat_ref": {"$ne": []}}
},
{
"$project": {"cat_ref": 0}
}
])
Example here

Related

How to add an array of objects in JSON

My question is entirely related to the structure of JSON. I've this:
{
"cars": {
"rows": [
{
"name": "Mercedes",
"color": "Black",
"make": "Mercedes"
},
{
"name": "BMW",
"color": "Black",
"make": "BMW Germany"
},
{
"name": "Innova",
"color": "Red",
"make": "Toyota"
}
]
}
}
Till now, row is an array of objects that contains information of different cars. I want two such row arrays. Only two are required. Like this:
{
"staticKpi": {
"rows": [
{
// 1st row 1st object
},
{
// 1st row 2nd object
},
{
// 1st row 3rd object
}
],
[
{
// 2nd row 1st object
},
{
// 2nd row 2nd object
},
{
// 2nd row 3rd object
}
]
}
}
You can see this JSON here.
But this is giving me JSON error. I just want to keep two lines of objects so there will be only two arrays in rows. hope I was able to explain the problem. Please correct my mistake.
PS: I've run forEach loop later on this JSON. So I've to take care of that too.
Try like this:
{
"staticKpi":{
"rows":[
[
{
"name":"Mercedes",
"color":"Black",
"make":"Mercedes"
},
{
"name":"BMW",
"color":"Black",
"make":"BMW Germany"
},
{
"name":"Innova",
"color":"Red",
"make":"Toyota"
}
],
[
{
"name":"Mercedes",
"color":"Black",
"make":"Mercedes"
},
{
"name":"BMW",
"color":"Black",
"make":"BMW Germany"
},
{
"name":"Innova",
"color":"Red",
"make":"Toyota"
}
]
]
}
}
rows needs to be one object/array, it can't be two. To have more than one element, you need to put those two elements in an array.
EDIT:
To loop through these using forEach in JavaScript, you could do this:
data = {"staticKpi":{"rows":[[{"name":"Mercedes","color":"Black","make":"Mercedes"},{"name":"BMW","color":"Black","make":"BMW Germany"},{"name":"Innova","color":"Red","make":"Toyota"}],[{"name":"Mercedes","color":"Black","make":"Mercedes"},{"name":"BMW","color":"Black","make":"BMW Germany"},{"name":"Innova","color":"Red","make":"Toyota"}]]}};
data.staticKpi.rows.forEach((row) => console.log(row));

Change subelement with jq

I have a structure that looks like so
[
[
{
"ID": "grp1-001",
},
{
"ID": "grp1-002",
},
{
"ID": "grp1-003",
},
{
"ID": "grp1-004",
},
{
"ID": "grp1-005",
},
{
"ID": "grp1-006",
}
],
[
{
"ID": "grp2-001",
},
{
"ID": "grp2-002",
},
{
"ID": "grp2-003",
},
{
"ID": "grp2-004",
},
{
"ID": "grp2-005",
},
{
"ID": "grp2-006",
}
.......
what I need to get as a result of the modification is this
[
[
["1", "grp1-001"],
["2", "grp1-002"],
["3", "grp1-003"],
["4", "grp1-004"],
["5", "grp1-005"],
["6", "grp1-006"],
],
[
["1", "grp2-001"],
["2", "grp2-002"],
["3", "grp2-003"],
["4", "grp2-004"],
["5", "grp2-005"],
["6", "grp2-006"],
],
Which means I need to keep the external structure (outside array and an internal grouping) but convert the inner dict to an array and replace the "ID" key with a value (that will come from external source like --argjson). I am not even sure how to start - any ideas/resources are highly appreciated.
Assuming you're just taking the objects and transforming them to pairs of the index in the array and the ID value, you could do this:
map([to_entries[] | [.key + 1, .value.ID | tostring]])
https://jqplay.org/s/RBac7SPfdG
Using to_entries/0 on an array gives you an array of key/value (index/value) pairs. You could then shift the indices by 1 and convert to strings.

Hive Sql Query To get Json Object from Json Array

I have a json inside 'content' column in the following format:
{ "identifier": [
{
"type": {
"coding": [
{
"code": "MRN",
}
]
},
"value": "181"
},
{
"type": {
"coding": [
{
"code": "PID",
}
]
},
"value": "5d3669b0"
},
{
"type": {
"coding": [
{
"code": "IPN",
}
]
},
"value": "41806"
}
]}
I have to run an hive query to get the "value" of the code which is equal to "MRN".
I have written the following query but its not giving the value as expected:
select get_json_object(content,'$.identifier.value')as Mrn from Doctor where get_json_object(content,'$.identifier.type.coding.code') like '%MRN%'
I dont want to give particular array position like:
select get_json_object(content,'$.identifier[0].value')as Mrn from Doctor where get_json_object(content,'$.identifier[0].type.coding.code') like '%MRN%'
As the json gets created randomly and the position is not fixed always.
Give [ * ] to avoid giving position.
select get_json_object(content,'$.identifier[*].value')as Mrn from Doctor where get_json_object(content,'$.identifier[*].type.coding.code') like '%MRN%'

Query Nested Mongodb info with Variable Nested Field names

I have a MongoDB that is structured as below:
[
{
"subject_id": "1",
"name": "Maria",
"dob": "1/1/00",
"gender": "F",
"visits": {
"1/1/18": {
"date_entered": "1/2/18",
"entered_by": "Sally"
},
"1/2/18": {
"date_entered": "1/2/18",
"entered_by": "Tim",
}
},
"samples": {
"XXX123": {
"collected_by": "Sally",
"collection_date": "1/3/18"
}
}
},
{
"subject_id": "2",
"name": "Bob",
"dob": "1/2/00",
"gender": "M",
"visits": {
"1/3/18": {
"date_entered": "1/4/18",
"entered_by": "Tim"
}
},
"samples": {
"YYY456": {
"collected_by": "Sally",
"collection_date": "1/5/18"
},
"ZZZ789": {
"collected_by": "Tim",
"collection_date": "1/6/18"
},
"AAA123": {
"collected_by": "Sally",
"collection_date": "1/7/18"
}
}
}
]
If I wanted to query the database to find all samples collected by Sally or all visits entered by Tim, what would be the best way of doing that?
I'm new to MongoDB and my attempts with various regex's haven't produced results. Any advice would be greatly appreciated.
I first used project on the required fields to use objectToArray followed by unwind to create separate records for array created in project.
The results are then filtered using match.
This works for the data provided in the question -
db.so.aggregate([
{$project: {visits: {$objectToArray: "$visits"}, samples: {$objectToArray: "$samples"}}},
{$unwind: "$visits"},
{$unwind: "$samples"},
{ $match: {
$or : [
{ "visits.v.entered_by" : "Tim" },
{ "samples.v.collected_by" : "Sally" }
]
}
}
])

MongoDB - How to $inc in a double nested array

I'm trying to increment c every time a user choose a label.
My sample dataset has two nested arrays:
{
"id": 123,
"labels": [
{
"label": "orange",
"hitCount": 2,
"hits": [
{
"who": "bob",
"c": "2"
}
]
},
{
"label": "red",
"hitCount": 6,
"hits": [
{
"who": "bob",
"c": "5"
},
{
"who": "alice",
"c": "1"
}
]
}
]
}
For example bob choose again red so I want to increment the c inside bob's object inside red's object from 5 to 6.
I can't use $ two times to navigate inside more than one array per https://docs.mongodb.com/manual/reference/operator/update/positional/#nested-arrays
So anyone knows how to traverse more than one level of array and obtain a reference for $inc?
I suggest you to change you data model to:
{
"id": 123,
"labels": [
{
"label": "orange",
"hitCount": 2,
"hits": {
"bob": 2
}
},
{
"label": "red",
"hitCount": 6,
"hits": {
"bob":5,
"alice":1
}
}
]
}
Then you could update hits using this command:
db.hits.update(
{ 'labels.label': 'red' },
{ '$inc': { 'labels.$.hitCount': 1, 'labels.$.hits.bob': 1 } }
);
If you need to construct update with dynamic username, you can do it:
var userName = 'bob';
var updateCommand = {
$inc: {
'labels.$.hitCount': 1
}
};
updateCommand.$inc['labels.$.hits.' + userName] = 1;
db.hits.update({ 'labels.label': 'red' }, updateCommand);