I use MySql, all relationships have been configured correctly in models and schemas:
I have 3 tables:
1. posts ( main )
2. categories ( 1 post has 1 cat, 1 cat belongs to many posts )
3. tags ( many-to-many )
Categories and tags both have "post_id" column relating to "id" column in posts table.
What is the best way to get all related data ( post data + post category data + post tags data ) ?
( for now I know I can get something like:
const post = await Post.find(params.id)
const category = await post.categories().fetch()
etc for every related table
I'm sure there must be better way.
I'd like result to be:
{
post data - name, text ...,
"category": {
category data - name, text ...
},
"tags": [
{
tag1 data
},
{
tag2 data
}
]
}
const wantedData = await Post.query().where('id', params.id).with('categories').with('tags').fetch()
Yes, there is a better way to do this.
The Latest Adonis js Have the feature of the Query builder. You can perform almost all SQL queries using this. For Example
#select
Database
.from('users')
.select('id', 'username', 'email')
So There are many queries you can perform as your need. The following links will be very useful for you. Query builder Documentation
Related
So supabase allows for two tables pretty simply.
const { data, error } = await supabase
.from('table1')
.select('table1.thing1, table1.thing2, table2(table2.thing2, table2.thing3)')
.console.log(data)
What I am trying to do is access a 3rd table to get information from table2 but I need table 1 to have the data.
const { data, error } = await supabase
.from('table1')
.select('table1.thing1, table2.thing2, table2(table2.thing2, table2.thing3), table3(table3.thing2, table3.thing2)')
console.log(data)
I would expect this to give me a data across all 3 but I just get a null returned.
With #supabase if you want to connect more than one table via supabasejs query your best bet is to just make a view. I hope this helps someone else out there!
I need help tweaking the code for this:
const posts = await PostMessage.find({ $or: [ { title }, { tags: { $in: tags.split(',') } } ]});
At the moment, you can filter for posts using a search form which has title and posts. You can leave one empty when you search. It works fine except when you use both. For example searching “hiking” and tagging “Europe” would show posts for both hiking titles AND Europe tags (when I would want the search narrowed down to only show posts with the title hiking and tagged Europe). I know that I can use $and in place of $or but that only returns posts if the user enters both title and tags when I want to give the user the option to leave one blank. Can someone help me write out the code for that?
From what I’ve seen I was wondering if I could do something like this:
Or: {
(And: title not null, tags not null )
(Or title null, tags not null)
(Or title not null, tags null)
)
Is this possible to do? I can’t find a similar example. Thanks for the help!
Assuming that none of the parameters (title,tags) will be undefined you can design query before you run it
const query = {
title: title,
tags: { $in: tags.split(",") },
};
const params = { title, tags };
Object.keys(params).forEach((param) => {
if (!params[param]) {
delete query[param] // delete from query if value is not present
}
});
const posts = await PostMessage.find(query);
This way it will use only the parameters that have values
Im using supabase with a database which have 2 tables (that are implicates in this issue).
Tables are teachers and users. Both have ID and id_teacher/id_user respectively.
Im working in a query where i need to get all teacher, joining in users table, where theres a image column.
I need just to get the teachers where the user have an not null image.
const query = supabase.from(`teachers`).select(
`
*,
id_user(
image
)
`
)
This query works to get teachers joining in users table. Because i get my wanted response.
This is a short example.
{
"id": 560,
"teacher_experience": 9,
"id_user":{
"image": "example-image.jpg"
}
}
The trouble is when i try to use some filter to avoid null images.
query.not('id_user.image', 'eq', null)
query.not('id_user.image', 'in', null)
query.ilike('id_user.image', 'null')
Are just an examples o filters tha i tryed for avoid the teachers which user.image have a null value.
Because, i want to NOT GET the entire item, but i get an item wiht a id_user = null
{
"id": 560,
"teacher_experience": 9,
"id_user": null // In this case image is null but still giving me the user
}
How is the correct form to solve this?
Just create a view in database for solve this problem. A view is a shortcut to queries and it possible apply where clause.
In sql editor on supabase https://app.supabase.io/project/{your_project_id}/editor/sql
create a new view with joins;
CREATE VIEW teachers_view AS
SELECT
t.*,
iu.image as image
FROM teachers as t
LEFT JOIN id_user as iu WHERE t.id = iu.teacher_id;
read more about left join here
and in application use
supabase.from('teachers_view').select().neq('image', null);
This has now been implemented with PostgREST 9!
Here's an example:
const { data, error } = await supabase
.from('messages')
.select('*, users!inner(*)')
.eq('users.username', 'Jane'
In your, case you'd have to do id_user!inner(image)
Source: https://supabase.com/blog/postgrest-9#resource-embedding-with-inner-joins
query.not("your_column_name", "is", "NULL")
worked for me!
odd enough, if you want to check for NULL
.filter("your_column_name", "is", "NULL")
seems to be the solution. No idea why it's not consistent
It is not possible atm.
You can see state of issue here.
Some posibilities are using views o start the query in the other table.
The Supabase client uses postgrest, so you can use all sorts of operators in your queries. See this page as a reference.
This feature came up recently with the release of the support for PostgREST 9. You have to use !inner keyword, you can now filter rows of the top-level table.
const query = supabase.from(`teachers`).select(
`
*,
id_user!inner(image)
`
).not("id_users.image", "is", "NULL")
you can try like with inner joins by using the !inner operator in select
const query = supabase.from(`teachers`).select(
`
*,
id_user!inner(
image
)
`
)
TL;DR
products have multiple categories.
View should show only all subcategories and products that have the category assigned.
How to setup the DB and queries?
I'm learning Vue and Firebase at the moment coming from a C# and SQL background, I need some help and advice on the noSQL side of things.
EDIT: categories and products are two separate collections (at the moment).
I have products, which can have multiple categories (see product 5)
products: {
prod1-id: {
name:'apple-type-A',
price: 2
cats: cat1-id
}
prod2-id: {
name:'apple-type-B',
price: 2.5
cats: cat1-id
}
prod3-id: {
name:'banana-type-A',
price: 1.6
cats: cat2-id
}
prod4-id: {
name:'banana-type-B',
price: 1.9
cats: cat2-id
}
prod5-id: {
name:'smoothie',
price: 5,
cats: [cat2-id, subCat1-id, subCat2-id]
}
}
Those categories are a tree.
categories: {
cat1-id: {
name: 'fruits',
subCat1-id: {
name: 'apple'
}
subCat2-id: {
name: 'banana'
}
},
cat2-id: {
name: 'MySmooth'
}
}
The customer should see the first tree.
The landing page should only show the first depth of the category tree and every product without a category (maybe add a category called 'no category').
When you click on a category is should show all the subcategories and products, that have this category.
This goes on until the deepest branch.
I tried to sketch my idea:
VIEW
For programming I use Vue, with vuex and vuexfire and as framework Vuetify.
I have the complete product management setup but I don't know how to query for this view.
My idea was to reuse a <v-card v-for="p of products"> I already have and is working fine.
But this shows only products, not categories. How do I get the categories into the mix?
QUERY
Working with vuexfire this is quite simple.
bindSoldProducts: firestoreAction(({ bindFirestoreRef }) => bindFirestoreRef('products', productsColl.where('isSold', '==', true))
but how can I get the categories and products now show side by side?
I've started to get the products together by querying, but have no idea how to put the categories into the mix:
firebase.firestore.collection('products').orderBy('name', 'asc').onSnapshot(snap => {
const productsArray: any = []
snap.forEach(doc => {
const product = doc.data()
product.id = doc.id
productsArray.push(product)
})
store.commit('setAllProducts', productsArray)
})
Do I need to structure my database differently?
Do I just query the products and use "some js logic/magic" to show the categories? But how would I then get the views.
Are the collection group queries of firebase the right way to go? If yes, how?
Please advice
Try a for in all Categories and get the fruits:
const categories = {
"cat1-id": []
}
Object.keys(categories).forEach(cat => {
const res = db.collection('products').where('cats', 'array-contains', cat).get()
// Resolve and put (push) in categories[cat]
})
See: https://firebase.google.com/docs/firestore/query-data/queries
I'm writing my response an answer as it was too long for a comment.
If I understood your use case correctly, you want to have a DB structure where you have a list of products and their respective categories which both will be displayed simultaneously side by side on your Vue application view.
While I'm not a Vue expert, I can suggest using the following structure for your Cloud Firestore database: Products/{product}/categories/{category}, which translates to collection/{document}/collection/{document}.
In the Cloud Firestore data model you can have a collection within another collection, and this is called a subcollection. For example, you could have Products/fruits/Categories/banana and inside the banana document you could have type, price, or id fields among many others.
Then, you could use Collection group queries to retrieve documents from a collection group instead of from a single collection. A collection group consists of all collections with the same ID. By default, queries retrieve results from a single collection in your database.
For example, you could create a categories collection group by adding a Categories subcollection to each product and then retrieve results from every product's categories subcollection at once, let's say bananas:
const querySnapshot = await db.collectionGroup('categories').where('productName', '==', 'banana').get();
querySnapshot.forEach((doc) => {
console.log(doc.id, ' => ', doc.data());
// Banana from Mexico, Banana from Honduras, etc.
});
Before using a collection group query, do not forget to create an index that supports your collection group query. You can create an index through an error message, the console, or the Firebase CLI.
What's the easiest way to fetch the number of comments and the number of likes a post has?
I don't see any usefull field when fetching a post (with a request like https://site/wp-json/wp/v2/posts?after=2018-07-21T15:05:44.000Z)
I'm currently using javascript issuing direct requests with axios.
If you have edit access to the code of the site your are requesting, you could add the field to the responses provided by the JSON API.
Something like this:
add_action( 'rest_api_init', function() {
\register_rest_field( 'post', 'comment_count', [
'get_callback' => function ( $post ) {
return (int) wp_count_comments( $post['id'] )->approved;
},
'schema' => [
'description' => 'List number of comments attached to this post.',
'type' => 'integer',
],
] );
});
If you don't have access to the site you are requesting, you can have the comments added to the response by send ?_embed=true at the end of the URL and simply count the replies.
Something like this:
const {data} = await Axios.get( 'https://site/wp-json/wp/v2/posts?after=2018-07-21T15:05:44.000Z&_embed=true' );
data.map( post => {
console.log( post._embedded.replies.length );
});
Not so much a JavaScript related question but here's an answer anyway.
The easiest way to get the number of comments for any post aside from adding a custom endpoint to the REST API is to use the comments endpoint (https://site/wp-json/wp/v2/comments?post=1234&per_page=1) and use the response's X-WP-Total header.