N1QL document containing list of objects query - couchbase

I am fairly new to N1QL queries. I have some documents like this.
[
{
"id":"id_1",
"data":{
"name":"name_1"
},
"type":"type_1"
},
{
"id":"id_2",
"data":{
"name":"name_2"
},
"type":"type_2"
},
{
"id":"id_3",
"data":{
"name":"name_3"
},
"type":"type_3"
}
]
what index should i create to be able to get all the documents that have the "type"="type_3" ?

You can create an index like the one below to index all the documents of type type_3.
create index idx_type_3 on `bucket_name`.scope.collection(data) where type="type_3"

Related

How do I properly use deleteMany() with an $and query in the MongoDB shell?

I am trying to delete all documents in my collection infrastructure that have a type.primary property of "pipelines" and a type.secondary property of "oil."
I'm trying to use the following query:
db.infrastructure.deleteMany({$and: [{"properties.type.primary": "pipelines"}, {"properties.type.secondary": "oil"}] }),
That returns: { acknowledged: true, deletedCount: 0 }
I expect my query to work because in MongoDB Compass, I can retrieve 182 documents that match the query {$and: [{"properties.type.primary": "pipelines"}, {"properties.type.secondary": "oil"}] }
My documents appear with the following structure (relevant section only):
properties": {
"optional": {
"description": ""
},
"original": {
"Opername": "ENBRIDGE",
"Pipename": "Lakehead",
"Shape_Leng": 604328.294581,
"Source": "EIA"
},
"required": {
"unit": null,
"viz_dim": null,
"years": []
},
"type": {
"primary": "pipelines",
"secondary": "oil"
}
...
My understanding is that I just need to pass a filter to deleteMany() and that $and expects an array of objects. For some reason the two combined isn't working here.
I realized the simplest answer was the correct one -- I spelled my database name incorrectly.

Postgres - updating an array element in a json column

I have a json column in a postgres table.
The column contains the following json data:
{
"data": {
"id": "1234",
"sites": [
{
"site": {
"code": "1",
"display": "Site1"
}
},
{
"site": {
"code": "2",
"display": "Site2"
},
"externalSite": true
},
{
"site": {
"code": "3",
"display": "Site3"
}
}
]
}
}
I need to create an update query that adds another attribute ('newAttribute' in the sample below) to all array items that have '"externalSite": true', so, after running the update query the second array element will be:
{
"site": {
"code": "2",
"display": "Site2"
},
"externalSite": true,
"newAttribute": true
}
The following query returns the array elements that need to be updated:
select * from myTable, jsonb_array_elements(data -> 'sites') sites
where sites ->'externalSite' = 'true'
What is the syntax of the update query?
Thanks
Kobi
Assuming your table is called test and your column is called data, you can update it like so:
UPDATE test SET data =
(select jsonb_set(data::jsonb, '{"data","sites"}', sites)
FROM test
CROSS JOIN LATERAL (
SELECT jsonb_agg(CASE WHEN site ? 'externalSite' THEN site || '{"newAttribute":"true"}'::jsonb
ELSE site
END) AS sites
FROM jsonb_array_elements( (data#>'{"data","sites"}')::jsonb ) as ja(site)
) as sub
);
Note that I cast the data to jsonb data as there are more functions and operators available for manipulating jsonb than plain json.
You can run the SELECT statement alone to see what it is doing, but the basic idea is to re-create the sites object by expanding it with jsonb_array_elements and adding the newAttribute attribute if externalSite exists.
This array is then aggregated with jsonb_agg and, finally, in the outer select, the sites object is replaced entirely with this newly computed version.

Cloudant/Mango selector for deeply nested JSONs

Let's say some of my documents have the following structure:
{
"something":{
"a":"b"
},
"some_other_thing":{
"c":"d"
},
"what_i_want":{
"is_down_here":[
{
"some":{
"not_needed":"object"
},
"another":{
"also_not_needed":"object"
},
"i_look_for":"this_tag",
"tag_properties":{
"this":"that"
}
},
{
"but_not":{
"down":"here"
}
}
]
}
}
Is there a Mango JSON selector that can successfully select on "i_look_for" having the value "this_tag" ? It's inside an array (i know its position in the array). I'm also interested on filtering the result so I only get the "tag_properties" in the result.
I have tried a lot of things, including $elemMatch but everything mostly return "invalid json".
Is that even a use case for Mango or should I stick with views ?
With Cloudant Query (Mango) selector statements, you still need to define an appropriate index before querying. With that in mind, here's your answer:
json-type CQ index
{
"index": {
"fields": [
"what_i_want.is_down_here.0"
]
},
"type": "json"
}
Selector against json-type index
{
"selector": {
"what_i_want.is_down_here.0": {
"i_look_for": "this_tag"
},
"what_i_want.is_down_here.0.tag_properties": {
"$exists": true
}
},
"fields": [
"_id",
"what_i_want.is_down_here.0.tag_properties"
]
}
The solution above assumes that you always know/can guarantee the fields you want are within the 0th element of the is_down_here array.
There is another way to answer this question with a different CQ index type. This article explains the differences, and has helpful examples that show querying arrays. Now that you know a little more about the different index types, here's how you'd answer your question with a Lucene search/"text"-type CQ index:
text-type CQ index
{
"index": {
"fields": [
{"name": "what_i_want.is_down_here.[]", "type": "string"}
]
},
"type": "text"
}
Selector against text-type index
{
"selector": {
"what_i_want.is_down_here": {
"$and": [
{"$elemMatch": {"i_look_for": "this_tag"}},
{"$elemMatch": {"tag_properties": {"$exists": true}}}
]
}
},
"fields": [
"_id",
"what_i_want.is_down_here"
]
}
Read the article and you'll learn that each approach has its tradeoffs: json-type indexes are smaller and less flexible (can only index specific elements); text-type is larger but more flexible (can index all array elements). And from this example, you can also see that the projected values also come with some tradeoffs (projecting specific values vs. the entire array).
More examples in these threads:
Cloudant Selector Query
How to index multidimensional arrays in couchdb
If I'm understanding your question properly, there are two supported ways of doing this according to the docs:
{
"what_i_want": {
"i_look_for": "this_tag"
}
}
should be equivalent to the abbreviated form:
{
"what_i_want.i_look_for": "this_tag"
}

Convert nested json to Cassandra

I run into a problem when trying to convert json data to Cassandra.
The json data is like:
{
"A": {
"A_ID" : "1111"
"field1": "value1",
"field2": "value2",
"field3": [
{
"id": "id1",
"name": "name1",
"segment": [
{
"segment_id": "segment_id_1",
"segment_name": "segment_name_1",
"segment_value": "segment_value_1"
},
{
"segment_id": "segment_id_2",
"segment_name": "segment_name_2",
"segment_value": "segment_value_2"
},
...
]
},
{
"id": "id2",
"name": "name2",
"segment": [
{
"segment_id": "segment_id_3",
"segment_name": "segment_name_3",
"segment_value": "segment_value_3"
},
{
"segment_id": "segment_id_4",
"segment_name": "segment_name_4",
"segment_value": "segment_value_4"
},
...
]
},
...
]
}
}
Thank you very much!
I see a post about composite keys here:
https://pkghosh.wordpress.com/2013/07/14/storing-nested-objects-in-cassandra-composite_columns/
But I do not know what does this post mean because the author did not give a complete solution.
In such cases, you should keep entire json string in database.
For example – You can create a table for "segement" part of the json.
Create table segment_by_id{
Id text,
Name text,
Json text,
PRIMARY KEY (id, name)
WITH CLUSTERING ORDER BY (name DESC);
This way you can divide the json part by part. You can also save the entire json in one table with primary and clustering keys suitable to your needs.
Cassandra uses LZ4 compression so large data can be saved efficiently. Go through Compression documentation to use a compression algoritham for table.

Json array in mongoDB

I want to get objects according to an ID they have in an array in a json file in mongodb.
I tried a lot of ways to get them with no success:
db.collection.find({"Id":"2"})
db.collection.find({"Messages.Id":"2"})
db.collection.find({"Messages":{$elemMatch:{"Id":"2"}}})
db.collection.find({"Messages.Id":{$elemMatch:{"Id":"2"}}})
{
"Messages" : [
{
"text":"aaa",
"Id" : [ "1", "2" ]
},
{
"texts" : "bbb",
"Id" : [ "1", "3" ]
}
]
}
Even though that's how it's supposed to be done according to the mongodb documentation.
So I thought something was wrong with my json design (I tried changing it but that didn't help either).
Can anyone suggest to me a good design or query to get the objects with a certain id will work?
UPDATE:
I want for example that if in the query i request the id 2
only the first message and all of it will be displayed (I don't mind if the Id field wont be displayed)
{
"text":"aaa",
"Id":["1","2"]
}
To find single elements that match you will need to utilize the positional operator ($).
db.collection.find({"Messages.Id": "2"}, {"Messages.$": 1, _id: 0})
For finding multiple matches, you would use the aggregation pipeline:
db.collection.aggregate([
{ $unwind: "$Messages" },
{ $match: {"Messages.Id": "1"}},
{ $group: { _id: null, messages: { $push: "$Messages"}}}
])