Postgres: select data to jsonb object - postgresql-9.6

I'm new to json in postgres, so please don't throw anything at me. I'm trying to select data to jsonb object. I plan to use it for update from select. Right now it looks like this:
select to_jsonb(full_address) as full_address
from (
select "user".living_addr as living_id,
"user".living_addr_path as living_path,
null as living_house,
"user".address_level_id as registration_id,
"user".address_path as registration_path,
null as registration_house,
"user".work_addr as work_id,
"user".work_addr_path as work_path,
null as work_house,
public."user".user_id
from public."user"
) full_address
group by user_id, full_address
order by user_id
But I need also "living_id", "living_path", "living_house" to be into the object like this:
{
"living": {"id", "path", "house"}
}
and same for registration, work and learn.
Also, I don't need user_id in result object.
Tried to use subqueries like:
select to_jsonb(living) as living,
to_jsonb(registration) as registration,
...
from (
select "user".living_addr as id,
"user".living_addr_path as path,
null as house
from public."user"
) living,
(
select "user".address_level_id as id,
"user".address_path as path,
null as house
from public."user"
) registration
... etc
But, right now the result is wrong without grouping, and I can't find a clue how to use group by in this. There should be another simpler way I don't see.
The result object should look like this:
{
"work": {"id": ..., "path": [..., ...], "house": null},
"living": {"id": ..., "path": [..., ...], "house": null},
"registration": {"id": ..., "path": [..., ...], "house": null}
}
Is there a way to do this in postgres 9.6?

Yep, it's much more simple:
select jsonb_build_object(
'registration', jsonb_build_object('id', u.address_level_id, 'path', u.address_path, 'house', null),
'living', jsonb_build_object('id', u.living_addr, 'path', living_addr_path, 'house', null),
'work', jsonb_build_object('id', u.work_addr, 'path', u.work_addr_path, 'house', null)
)
from public.user u
And no update from select needed, just update.

Related

CakePHP 4 -> how to save join record

I'm working on a CakePHP 4 application and I've set up a join table between Categories and Products called CategoriesProducts.
When I'm creating a new Product with a property called categories_products which contains an array like:
[
[
'category_id' => `x`
]
]
What's supposed to be saved into the join table is the category_id with the newly generated product_id.
The data isn't saved to the join table.
In the saveMany function I pass the:
[
'associated' => [
'Categories'
]
]
When I try to add associated => CategoriesProducts I get an error that the relationship is not defined.
Can someone explain to me how I can fill the join table? I've setup the database and baked the models with the CakePHP helper.
Thanks in advance!
With the default association saving process you do not need to add data for join tables directly, instead you use the target association property and provide the primary keys of the records that you want to link.
So in your case that would probably be categories, eg your data for patching/creating an entity would be structured like this, where id is the primary key of the existing category that you want to associate to your new product:
[
// ...
'categories' => [
[
'id' => 123,
],
],
]
The ORM will then create the proper join table record automatically.
See also
Cookbook > Database Access & ORM > Saving Data > Converting BelongsToMany Data

Group by date and then by city on Rails

I have an api that its output must look like:
[
{
"store": "store",
"date": "2020/05/03",
"address": {
"city": "city1"
"address_line_1": "address"
},
"sales_count": 10,
},
{
"store": "store",
"date": "2020/05/03",
"address": {
"city": "city2"
"address_line_1": "address"
},
"sales_count": 21,
},
]
I know how to handle the grouping and the sales count, but I'm having issues with grouping by city
Store.first.sales.group(:date).count would be the sales_count but I'm not sure how to include the group by address.
Taking into account that address = Store.first.sales.first.address
This means that a store has many sales and each sale has an address.
Since you're not only just want to count sales but also return data, then you should prefer PARTITION BY to GROUP BY.
You can PARTITION BY combine date, address:
SELECT store, date, address,
COUNT(sales) OVER (PARTITION BY date, address) AS sales_count
FROM _
Beside that, if you do nothing with data but return them, then the best practice is just call sql directly from adapter (so we avoid the creation of ActiveRecord model objects was causing all sorts of memory contention problem)
result = ActiveRecord::Base.connection.execute(
"SELECT store, date, address,
COUNT(sales) OVER (PARTITION BY date, address) AS sales_count
FROM _"
)
result.each do |msg|
# json serialize ???
end

Rails find all with conditions

I want to search records on a Table based on an array of foreign key ids and trigger error if one of the ids doesn't exist, e.g.
pry(main)> Person.find([1, 2, 2002])
ActiveRecord::RecordNotFound: Couldn't find all Person
with 'id': (1, 2, 2002) [WHERE "persons"."deleted_at" IS
NULL] (found 2 results, but was looking for 3).
The problem is, the array of ids is not id, but parent_id which is a foreign key in Person. I want something like this, but it has deprecated:
Person.find(:all, :conditions => { :friends => ["Bob", "Steve", "Fred"] }
If I do like this,
Person.where(friends: ["Bob", "Steve", "Fred"])
it will just return 2 results instead of triggering error if Fred isn't found.
Thanks
You can use find_by method for column specific search.
Person.find_by(friends: ["Bob", "Steve", "Fred"])
Or
Person.find_by_friends(["Bob", "Steve", "Fred"])

Is it possible to upsert documents in mondodb by an array of ids, so that each new created document's _id is the one from the array?

In my Rails project with mongodb, I retrieve user ids from twitter which I want to store in my User model. The plan is to upsert the collection of Users with the retrieved user ids I have in an array, and set every new created document _id to the corresponding user id from the array.
So when I do something like this:
Tweep.collection.find( _id: 1234567 ).modify( { "$set" => {a: true}, "$unset" => {c: ""} }, {upsert: true})enter code here
The result is like expected: <Tweep _id: 1234567, a(active): true, c(candidate_value): nil>
Now I want to do the same, but only passing an array of ids to upsert my collection on Users:
Tweep.collection.find(_id: {"$in" =>[123124,223553,6343643,23423]}, c: { "$exists" => true }).modify( { "$set" => {p: true}, "$inc" => {c: 1} }, {upsert: true})
The result is some newly created documents, but without the desired values as _id e.g. _id: 123124:
<Tweep _id: 5244501325fed0cfd2c1a615, a(active): nil, c(candidate_value): 1>
instead of:
<Tweep _id: 123124, a(active): nil, c(candidate_value): 1>
How can I make mongodb use the user id in my array to be the id for the field _id?
Any help is highly appreciated.
That is not possible. From the documentation:
If upsert is set to true and if no document matches the query
criteria, update() inserts a single document.
Then again, you write:
The result is some newly created documents
I hope that it's really only one document. With a query that contains only _id : {$in : [...]}, it wouldn't even insert a single document on my machine (MongoDB 2.5.0). It only inserts if I add more criteria. Could you check that again?
It's hard to come up with a meaningful definition of how this should behave. Combining $in can be tricky. Let's say you have two documents:
{ _id : 1, name : "John" }
{ _id : 2, name : "Jane" }
and you call
db.update({"_id" : {$in : [1,2]}, "name" : "Max"}, { ... }, { upsert: true});
What is supposed to happen? There is no document that has _id 1 or 2 and name equals "Max", so the upsert would have to insert... well, what? Maybe two documents with the name Max? If the array were larger, we'd create a ton of 'Max's which probably wasn't our intention (the semantics would be: "update one or insert a thousand", which is odd). So let's say we only insert one. But now, which _id to choose? And, of course, there is the problem that _id is a unique key, so in the example, both would fail.

Rails query include? an array

I store an array of Section ids as integers. event.sections #=> ["1","115","130"]
There is no Events has_many Sections relationship. Maybe this is a problem. I only need id's from Section and nothing else, so I have the array of integers stored as a serialized string in Postgres.
I can do something like this, which returns an array of events:
Event.upcoming.select { |m| m.sections.include? #section.id.to_s}
Is there a way to query this to get back an ActiveRecord::Relation?
edit-----
My earlier select query is not correct, because if #section.id = "1" then it will match and select events with these id's "1", "10", "21", "100"
This is the proper select statement:
Event.upcoming.select {|e| ( e.newsletters.split(",").flatten.grep /^#{#section.id.to_s}$/ ).presence }

Resources