Postgres jsonb document storage like mongo - postgresql

I have simple table like this
CREATE TABLE things (
id SERIAL PRIMARY KEY,
data jsonb
);
and i want to store complex nested json like this
{
"id": 1,
"title": "thing",
"things": [
{
"title": "thing 1",
"moreThings": [
{ "title": "more thing 1" }
]
}
]
}
but i found it difficult to insert and manipulate complex nested json.
i want to do same thing as mongo's push and populate, can i achieve same functionality with postgres json storage? if i can how? or is it an anti pattern and i should just write normal tables with relations?

Related

DynamoDB PartiQL Query For Specific Map Element From List

I have a DynamoDB with data that looks like this:
{
"userId": {
"S": "someuserID"
},
"listOfMaps": {
"L": [
{
"M": {
"neededVal": {
"S": "ThisIsNeeded1"
},
"id": {
"S": "1"
}
}
},
{
"M": {
"neededVal": {
"S": "ThisIsNeeded2"
},
"id": {
"S": "2"
}
}
},
...
]
},
"userName": {
"S": "someuserName"
}
}
The listOfMaps can contain more than just 2 maps, as is denoted by the ellipsis. Is there a PartiQL query I can put together that will let me get the neededVal based on the userId and the id of the item in the map itself?
I know that I can query for the n-th item's neededVal like this:
SELECT "listOfMaps"[N]."neededVal"
FROM "table-name"
WHERE "userId" = 'someuserID'
But is it possible to make it do something like this:
SELECT "listOfMaps"."neededVal"
FROM "table-name"
WHERE "userId" = 'someuserID' AND "listOfMaps"."id" = '4'
It looks like you're modeling the one-to-many relationship using a complex attribute (e.g. a list of objects). This is a completely valid approach to modeling one-to-many relationships and is best used when 1) the results data doesn't change (or don't change often) and 2) you don't have any access patterns around the data within the complex attribute.
However, since you do want to perform searches based on data within the complex attribute, you'd be better off modeling the data differently.
For example, you might consider modeling results in the user partition with a PK=user_id SK=neededVal#. This would allow you to fetch items by User ID (QUERY where PK=USER#user_id SK begins_with neededVal#).
I don't know the specifics around your access patterns, but can say that you'll need to move results into their own items if you want to support access patterns around the data within your complex attribute.

How to structure NoSQL Documents in Azure for Lookup By Array of String contains?

NoSQL newbie here..
I have Employee documents and every Employee has a name and has one to many tags. Here is a possible representation of an employee object in JSON format:
{
"name": "John Doe",
"tags": ["blue", "red", "green"]
}
I want to be able to query Employee instances in Cosmos DB by their tags. For example, I want to find an Employee where tags contains 'green'. An Employee will not have too many tags, maybe up to 10 or 15 at most.
What is the best way to model the document structure for this use case? cosmos db documentation here suggests a structure akin to following for a reason I do not understand:
{
"name": "John Doe",
"tags": [
{
"name": "blue"
},
{
"name": "red"
}
]
}
Is there any reason to split a String array into child JSON objects like this?
How to model documents is totally based on your requirement, there is no strict rule for that.
For your doc structure, I did some test on my side and this all my test doc,4 docs in total:
I can use the query below to find out all employees that contain the "green" tag:
SELECT c.name,c.tags FROM c where ARRAY_CONTAINS(c.tags, "green")

On mongoimport, can I easily map a field to _id on json import?

I need to import a dataset that looks like the similar (abbreviated) dataset.
[
{
"itemId": 1,
"name": "Item",
"qty": "10"
},
...
]
The tricky part is that doing inserts indefinitely will not raise any exception, but the itemId field would represent a valid identifier equivalent to _id field if it could be accepted as such.
Does any option akin to --idField itemId exists?

Should I use selector or views in Cloudant?

I'm having confusion about whether to use selector or views, or both, when try to get a result from the following scenario:
I need to do a wildsearch for a book and return the result of the books plus the price and the details of the store branch name.
So I tried using selector to do wildsearch using regex
"selector": {
"_id": {
"$gt": null
},
"type":"product",
"product_name": {
"$regex":"(?i)"+search
}
},
"fields": [
"_id",
"_rev",
"product_name"
]
I am able to get the result. The idea after getting the result is to use all the _id's from the result set and query to views to get more details like price and store branch name on other documents, which I feel is kind of odd and I'm not certain is that the correct way to do it.
Below is just the idea once I get the result of _id's and insert it as a "productId" variable.
var input = {
method : 'GET',
returnedContentType : 'json',
path : 'test/_design/app/_view/find_price'+"?keys=[\""+productId+"\"]",
};
return WL.Server.invokeHttp(input);
so I'm asking for input from an expert regarding this.
Another question is how to get the store_branch_name? Can it be done in a single view where we can get the product detail, prices and store branch name? Or do I need to have several views to achieve this?
expected result
product_name (from book document) : Book 1
branch_name (from branch array in Store document) : store 1 branch one
price ( from relationship document) : 79.9
References:
Book
"_id": "book1",
"_rev": "1...b",
"product_name": "Book 1",
"type": "book"
"_id": "book2",
"_rev": "1...b",
"product_name": "Book 2 etc",
"type": "book"
relationship
"_id": "c...5",
"_rev": "3...",
"type": "relationship",
"product_id": "book1",
"store_branch_id": "Store1_branch1",
"price": "79.9"
Store
{
"_id": "store1",
"_rev": "1...2",
"store_name": "Store 1 Name",
"type": "stores",
"branch": [
{
"branch_id": "store1_branch1",
"branch_name": "store 1 branch one",
"address": {
"street": "some address",
"postalcode": "33490",
"type": "addresses"
},
"geolocation": {
"coordinates": [
42.34493,
-71.093232
],
"type": "point"
},
"type": "storebranch"
},
{
"branch_id": "store1_branch2",
"branch_name":
**details ommit...**
}
]
}
In Cloudant Query, you can specify two different kinds of indexes, and it's important to know the differences between the two.
For the first part of your question, if you're using Cloudant Query's $regex operator for wildcard searches like that, you might be better off creating a Cloudant Query index of type "text" instead of type "json". It's in the Cloudant docs, but see the intro blog post for details: https://cloudant.com/blog/cloudant-query-grows-up-to-handle-ad-hoc-queries/ There's a more advanced post on this that covers the tradeoffs between the two types of indexes https://cloudant.com/blog/mango-json-vs-text-indexes/
It's harder to address the second part of your question without understanding how your application interacts with your data, but there are a couple pieces of advice.
1) Consider denormalizing some of this information so you're not doing the JOINs to begin with.
2) Inject more logic into your document keys, and use the traditional MapReduce View indexing system to emit a compound key (an array), that you can use to emulate a JOIN by taking advantage of the CouchDB/Cloudant index sorting rules.
That second one's a mouthful, but check out this example on YouTube: https://youtu.be/0al1KnCKjlA?t=23m39s
Here's a preview (example map function) of what I'm talking about:
'map' : function(doc)
{
if (doc.type==="user") {
emit( [doc._id], null );
}
else if (doc.type==="edge:follower") {
emit( [doc.user, doc.follows], {"_id":doc.follows} );
}
}
The resulting secondary index here would take advantage of the rules outlined in http://wiki.apache.org/couchdb/View_collation -- that strings sort before arrays, and arrays sort before objects. You could then issue range queries to emulate the results you'd get with a JOIN.
I think that's as much detail that's appropriate for here. Hope it helps!

How to set unique compound index on json array elements?

I have table tags and json column translations inside. This column looks like this:
translations: [
{ text: "Tag1", language: "en-us" },
{ text: "Tag1_cn", language: "zh-cn" },
...
]
Is it possible to set unique index on text+language across all rows? I would like to prevent inserting tag with same text+language to the tags table. So far I was using two tables - tags and tags_translations however I wanted to avoid extra join when querying for tags.
e.g.
CREATE TABLE jsondemo (blah json);
INSERT INTO jsondemo(blah) VALUES ('[
{ "text": "Tag1", "language": "en-us" },
{ "text": "Tag1_cn", "language": "zh-cn" }]');