We have a list of recipes (recipe_id) and ingredients (ingredient_id). Every recipe can become an ingredient of another recipe and that child recipe can then hold more second level child recipes and so on. I need a recursive query that takes a recipe id (or an array of ids - how I have it setup now) and returns a NESTED table or array of all the ingredients of the main recipes and any child recipes.
We're using Postgresql / Supabase / PostgREST.
So far I've been able to create the recursive query as a RPC function that returns a table using UNION ALL. This gives me a flat table back and I can't definitively trace back an ingredient to a specific parent recipe (because the same recipe can be called as a child in multiple parent recipes). Not sure where to go from here? The only other option I've figured out so far is to have my API endpoint query each level one at a time, but it generates a lot of network requests =(
DESIRED OUTPUT
Super flexible on format, but it would be nice if I could get all the child components as a nested array like so:
[
{ id: 1,
recipe_id: 22,
item_id: 9,
item: "Croissant Dough",
...,
components: [
{ id: 2,
recipe_id: 1,
item_id: 33,
item: "Butter,
...,
components: []
},
{ id: 3,
recipe_id: 1,
item_id: 71,
item: "Wheat Flour",
...,
components: []
}
]
},
{ id: 1,
recipe_id: 29,
item_id: 4,
item: "Almond Filling",
...,
components: [
{ id: 2,
recipe_id: 29,
item_id: 16,
item: "Almond Meal,
...,
components: []
},
{ id: 3,
recipe_id: 29,
item_id: 42,
item: "Pastry Cream",
...,
components: [
{ id: 7,
recipe_id: 42,
item_id: 22,
item: "Egg Yolks",
...,
components: []
]
}
]
},
]
CURRENT RPC FUNCTION
CREATE or REPLACE FUNCTION recipe_components_recursive (recipeids text)
RETURNS TABLE (id int8, recipe_id int8, item_id int8, quantity numeric, unit_id int8, recipe_order int4, item text, visible bool, recipe bool, "unitName" varchar, "unitAbbreviation" varchar, "conversionFactor" float4, "metricUnit" int8, batch bool)
LANGUAGE plpgsql
AS $$
DECLARE
transformedjson int[] := recipeids;
BEGIN
RETURN QUERY
WITH RECURSIVE recipe_components_rec_query AS (
SELECT *
FROM recipe_components_items
WHERE recipe_components_items.recipe_id = ANY (transformedjson)
UNION ALL
SELECT o.id, o.recipe_id, o.item_id, o.quantity, o.unit_id, o.recipe_order, o.item, o.visible, o.recipe, o."unitName", o."unitAbbreviation", o."conversionFactor", o."metricUnit", o.batch
FROM recipe_components_items o
INNER JOIN recipe_components_rec_query n ON n.item_id = o.recipe_id AND n.recipe = true
) SELECT *
FROM recipe_components_rec_query;
END $$;
Related
Good day! Here is the sandbox react code that I'm using for a project involving MUI tables:
I have been racking my brain over this, but can't seem to get a solution. How can I add to this table column-wise instead of by row?
In line 57-67, the rows are created first and then they are populated row-wise, left-to-right by data.
The data given looks like this:
const data = [
{name: "sample_name",
calories: "19",
fat: "90",
carbs: 70,
protein: 90},
{name: "sample_name",
calories: "19",
fat: "90",
carbs: 70,
protein: 90},
]
What the lines I mentioned do is it takes 1 of the objects in the data and appends them row-wise
I work with a data that looks like this:
const name = ["richard","nixon"]
const calories = [9, 9, 0, 9, 0, 5, 8]
const fat = [10, 9 , 9]
const carbs = [11, 3, 4,5 ]
const protein = [1, 1]
I just want to be able to insert name data into the name column... and so on... this should also hopefully make it easier for me to dynamically insert more data for each column using TextField+button action
Seems to me like this is a data issue, not Material UI. You need to provide row and column data to a table, regardless of what library you use, that's just how tables are build. So if you are getting back data by columns, you need a reducer or a method to convert them into rows. Here is a super quick and dirty example:
const rawData = {
name: ["Ice cream", "Sno cone"],
calories: [32, 45]
};
let columns = Object.keys(rawData);
let rows = rawData.name.map((name, i) => {
return { name, calories: rawData.calories[i] };
});
/*
rows = ["name", "calories"]
columns = [
{ name: "Ice cream", calories: 32 },
{ name: "Sno cone", calories: 45 },
];
*/
Obviously, this is a quick example and not very extensible, but should lead you in a good direction. Perhaps a reducer which could build out row data more elegantly. However, this will allow you to build out the table as intended:
<TableContainer component={Paper}>
<Table>
<TableHead>
<TableRow>
{columns.map((i) => (
<TableCell>{i}</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{rows.map((row) => (
<TableRow key={row.name}>
<TableCell>{row.name}</TableCell>
<TableCell>{row.calories}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
I have 3 tables (in Supabase -> PostgreSQL):
posts(
id_post INT,
id_user INT NOT NULL,
PRIMARY KEY(id_post),
FOREIGN KEY(id_user) REFERENCES users(id_user)
);
users(
id_user INT,
PRIMARY KEY(id_user),
UNIQUE(pseudo_user),
);
follows(
id_following INT,
id_follower INT,
PRIMARY KEY(id_following , id_follower ),
FOREIGN KEY(id_following ) REFERENCES users(id_user),
FOREIGN KEY(id_follower ) REFERENCES users(id_user)
);
My query for the moment is supabase.from('posts').select('*, users(*)').execute();
The result will be
{[
id_post : 1,
users : {id_user: 1}
]}
But I want to check if a row exist in follows where 'id_follower' = 1 and 'id_following' = the user_id of the post
So I want:
{[
id_post : 1,
users : {id_user: 1, isFollowed: 1}
]}
If the current user follow the user of the post, otherwise it will be 0.
You can use match for filtering plus the count option.
const { data, count } = supabase
.from('follows')
.select('*', { count: 'exact' })
.match({ id_user: 1, id_following: user_id })
I didn't find documentation for Flutter, btw I think the syntax is similar of the javascript one.
https://supabase.com/docs/reference/javascript/filter#filter-embedded-resources
https://supabase.com/docs/reference/javascript/select#querying-with-count-option
Hello, I need your help please with 2 questions.
I have 2 Models
One to Many
(One) Customer{ id, names, dni} -> Invoice {id, date, ....customer_id} (Many)
1. How can I get this?
I need to consume the api "GET /api/invoices" and that the json return of this, in turn, returns an array
[{
id: 1,
date: '2022-01-01',
....invoice
customer: {
dni: 1,
names: 'Example'
}
},
{
id: 2,
date: '2022-01-02',
....invoice
customer: {
dni: 2,
names: 'Example 2'
}
},
]
So far what I have found in the sailsjs documentation are only examples with POPULATE, where they only show how to list the User model with its corresponding created ones (hasMany)
//var users = await User.find().populate('pets');
// The users object would look something like the following
// [{
// id: 123,
// firstName: 'Foo',
// lastName: 'Bar',
// pets: [{
// id: 1,
// breed: 'labrador',
// type: 'dog',
// name: 'fido',
// user: 123
// }]
// }]
//---This is not what I need.
Is there a function or configuration that I have not found?
Or would I do something like this?
Invoices.find().exec(async(err, invoices)=>{
if(invoices){
for(i = 0; i< invoices.length; i++){
const customer = await Customer.find({id: invoices[i].customer_id});
invoices[i].customer = customer;
}
});
The point is that this takes much longer than doing a query with join
const invoices = await sails.sendNativeQuery('SELECT * from INVOICE A A inner join CUSTOMER B on A.customer_id=B.id ', []);
But I don't know how to get a JSON with the previous structure if I do it by query
2. What is the best option that can solve my problem?
The populate method works in both directions: oneToMany, manyToMany, and manyToOne:
https://sailsjs.com/documentation/reference/waterline-orm/queries/populate
If any condition is required, you could check the details on the section Populating a collection association:
var usersNamedFinn = await User.find({ name:'Finn' })
.populate('currentSwords', {
where: {
color: 'purple'
},
limit: 3,
sort: 'hipness DESC'
});
I am working on a JSON stream related to Malaria medicine availability in Zambia and have come across an issue I can't seem to find an answer for online. I am being sent JSON that looks like the one below.
{
"Country": "Zambia",
"City": "Lusaka",
"Area": [
"Northmead"
],
"MalariaMedicine": [
{
"pharmacyName": "Northmead Health",
"brand": "Chloroquin",
"quantity": 65,
"batchNumber": "CHLORO 628 C",
"bestBeforeDate": "2025-05-23",
"expired": false,
"batchInformation": {
"number": "CHLORO 628 C",
"expiration": "2025-01-23"
}
},
{
"pharmacyName": "Prime Pharmacy",
"brand": "Quinin",
"quantity": 205,
"batchNumber": "QUIN 560 Q",
"bestBeforeDate": "2028-01-01",
"expired": false,
"batchInformation": {
"number": "QUIN 560 Q",
"expiration": "2028-01-01"
}
}
]
}
I have pushed the JSON into a topic called Malaria and I used the code below to create a JSON stream.
CREATE STREAM MALARIASTREAM
(
COUNTRY STRING,
CITY STRING,
AREA ARRAY<STRING>,
MALARIAMEDICINE ARRAY<STRUCT<PHARMACYNAME STRING, BRAND STRING, QUANTITY INTEGER, BATCHNUMBER STRING, BESTBEFOREDATE STRING, EXPIRED BOOLEAN, BATCHINFORMATION STRUCT<NUMBER STRING, EXPIRATION STRING>>>
)
WITH (KAFKA_TOPIC='Malaria', KEY_FORMAT='KAFKA', VALUE_FORMAT='JSON');
The issue I have comes when I try to extract the data using the SELECT statement below
SELECT
COUNTRY,
CITY,
EXPLODE(AREA) AS AREA,
EXPLODE(MALARIAMEDICINE)->pharmacyName,
EXPLODE(MALARIAMEDICINE)->brand,
EXPLODE(MALARIAMEDICINE)->quantity,
EXPLODE(MALARIAMEDICINE)->batchNumber,
EXPLODE(MALARIAMEDICINE)->bestBeforeDate,
EXPLODE(MALARIAMEDICINE)->expired
FROM
MalariaStream EMIT CHANGES;
In the result set returned, the value of the AREA column is NULL for the second row. Both pharmacies are in the Northmead area so I want the second row to say Northmead as well.
How do I get the second row to also say Northmead?
If you know that you will always have one element arrays, you could use ELT(1, Area) to select the first element of that singleton array.
https://docs.ksqldb.io/en/latest/developer-guide/ksqldb-reference/scalar-functions/#elt
I will go with an example.
Say I have three tables defined like this:
(pseudocode)
Realm
id: number, pk
name: text, not null
Family
id: number, pk
realm_id: number, fk to Realm, pk
name: text, not null
Species
id: number, pk
realm_id: number, fk to Family (and therefore to Realm), pk,
family_id: number, fk to Family, pk,
name: text, not null
A temptative case classes definition would be
case class Realm (
id: Int,
name: String
)
case class Family (
id: Int,
realm: Realm,
name: String
)
case class Species (
id: Int,
family: Family,
name: String
)
If I make a json out of this after querying the database it would look like this:
SELECT *
FROM realm
JOIN family
ON family.realm_id = realm.id
JOIN species
ON species.family_id = family.id
AND species.realm_id = family.realm_id
Example data:
[{
"id": 1,
"family": {
"id": 1,
"name": "Mammal",
"realm": {
"id": 1,
"name": "Animal"
}
},
"name": "Human"
},
{
"id": 2,
"family": {
"id": 1,
"name": "Mammal",
"realm": {
"id": 1,
"name": "Animal"
}
},
"name": "Cat"
}]
Ok, so far... This is usable, if I need to show every species grouped by realm, I would transform the JsValue or in javascript do filters, etc. However when posting data back to the server, these classes seem a little awkward. If I want to add a new species I would have to post something like this:
{
"id": ???,
"family": {
"id": 1,
"name": "Mammal", // Awkward
"realm": {
"id": 1,
"name": "Animal" // Awkward
}
},
"name": "Cat"
}
Should my classes be then:
case class Realm (
id: Int,
name: Option[String]
)
case class Family (
id: Int,
realm: Realm,
name: Option[String]
)
case class Species (
id: Option[Int],
family: Family,
name: String
)
Like this, I can omit posting what it seems to be unnecesary data, but then the classes definition don't reflect what is in the database which are not nullable fields.
Queries are projection of data. More or like Table.map(function) => Table2. When data is extracted from the database and I don't get the name field, it doesn't mean it is null. How do you deal with this things?
One way to deal with it is to represent the interconnection using other data structures instead of letting each level know about the next.
For example, in the places where you need to represent the entire tree, you could represent it with:
Map[Realm, Map[Family, Seq[Species]]]
And then just Realm in some places for example as a REST/JSON resource, and maybe (Species, Family, Realm) in some place where you only want to work with one species but need to know about the other two levels in the hierarchy.
I would also advice you to think two or three times about letting your model structure define your JSON structure, what happens with the codes that consumes your JSON when you change anything in your model classes? (And if you really want that, do you actually need to go via a model structure, why not build your JSON directly from the database results and skip one level of data transformation?)