I have a blog application. I need to make a MongoDB query (SQL is fine, I'll translate it), to get a specific post in the blog, and the immediate posts made before and after that post.
For instance, given this list of posts:
12/01/13 - Foo
15/01/13 - Bar
17/01/13 - Baz
27/01/13 - Taz
How do I write a query so that I get one of these, i.g Bar, and the immediate siblings Foo and Baz?
I'd like to do this without making three different queries to the database, for performance reasons.
In my application I fetch a single post like this:
model.findOne({
date: {
$gte: new Date(2013, 0, 15),
$lt: new Date(2013, 0, 15, 24)
},
slug: 'Bar'
}, function(result){
return { entry: result };
});
Here's one possibility (involving 2 queries, one to find the primary post, and the second to find the nearest doc):
Treat the data/posts as if it were a doubly-linked list.
You'll need to store reference IDs as links to the "previous" and "next" posts in each post document (array). This makes inserts a tiny more complex, but inserting a "new" blog post by date somewhere in the past seems unlikely.
Index the link field
Search for documents having the id of the primary document $in the link field
Related
I have these 2 words:
The words in mysql db
And I have this category:
The category
As we can see in the word-table, the words have also a categoryId attribute.
I've made an junctiontable in case I need it but it's currently empty, it looks like that:
junction table
I want to display a list in my ui that is a admin-panel that would look like this for example:
Words
Category
God
Religion
Ford Mustang
Cars
Every word has exactly one category.
To do that I want to use axios to fetch a get request of my node.js server.
What would look the get method with the corresponding sequelize query to get the data and maybe also the method in the react ui?
I'm trying to figure it out for about two days now and I can't get out of this shithole...
What is the project*:**
Full stack web app that simulates the game "wheel of fortune". Contains a auth-system where admins can also make CRUD options for words, questions and create categories that belong to a word or question. Classic users can only play the game.
Technologies:
React -> Frontend
Node.js Backend -> Express.js and Sequelize
Database: MySQL with mysql workbench
Assuming model name for Words table is Word and Category for category table the code to query all the data would be such:
const words = await Word.findAll({
where: {
// here you can do filtering if needed
},
include: [
{
model: Category,
attributes: [
'category',
],
as: 'categories',
},
],
});
This will return list of words and associated categories. Then you would just create api endpoint and return queried data and display on frontend.
As part of a tool I am creating for my team I am connecting to an internal web service via PowerQuery.
The web service returns nested JSON, and I have trouble parsing the JSON data to the format I am looking for. Specifically, I have a problem with extracting the content of records in a column to a comma separated list.
The data
As you can see, the data contains details related to a specific "race" (race_id). What I want to focus on is the information in the driver_codes which is a List of Records. The amount of records varies from 0 to 4 and each record is structured as id: 50000 (50000 could be any 5 digit number). So it could be:
id: 10000
id: 20000
id: 30000
As requested, an example snippet of the raw JSON:
<race>
<race_id>ABC123445</race_id>
<begin_time>2018-03-23T00:00:00Z</begin_time>
<vehicle_id>gokart_11</vehicle_id>
<driver_code>
<id>90200</id>
</driver_code>
<driver_code>
<id>90500</id>
</driver_code>
</race>
I want it to be structured as:
10000,20000,30000
The problem
When I choose "Extract values" on the column with the list, then I get the following message:
Expression.Error: We cannot convert a value of type Record to type
Text.
If I instead choose "Expand to new rows", then duplicate rows are created for each unique driver code. I now have several rows per unique race_id, but what I wanted was one row per unique race_id and a concatenated list of driver codes.
What I have tried
I have tried grouping the data by the race_id, but the operations allowed when grouping data do not include concatenating rows.
I have also tried unpivoting the column, but that leaves me with the same problem: I still get multiple rows.
I have googled (and Stack Overflowed) this issue extensively without luck. It might be that I am using the wrong keywords, however, so I apologize if a duplicate exists.
UPDATE: What I have tried based on the answers so far
I tried Alexis Olson's excellent and very detailed method, but I end up with the following error:
Expression.Error: We cannot convert the value "id" to type Number. Details:
Value=id
Type=Type
The error comes from using either of these lines of M code (one with a List.Transform and one without):
= Table.Group(#"Renamed Columns", {"race_id", "begin_time", "vehicle_id"},
{{"DriverCodes", each Text.Combine([driver_code][id], ","), type text}})
= Table.Group(#"Renamed Columns", {"race_id", "begin_time", "vehicle_id"},
{{"DriverCodes", each Text.Combine(List.Transform([driver_code][id], each Number.ToText(_)), ","), type text}})
NB: if I do not write [driver_code][id] but only [id] then I get another error saying that column [id] does not exist.
Here's the JSON equivalent to the XML example you gave:
{"race": {
"race_id": "ABC123445",
"begin_time": "2018-03-23T00:00:00Z",
"vehicle_id": "gokart_11",
"driver_code": [
{ "id": "90200" },
{ "id": "90500" }
]}}
If you load this into the query editor, convert it to a table, and expand out the Value record, you'll have a table that looks like this:
At this point, choose Expand to New Rows, and then expand the id column so that your table looks like this:
At this point, you can apply the trick #mccard suggested. Group by the first columns and aggregate over the last using, say, max.
This last step produces M code like this:
= Table.Group(#"Expanded driver_code1",
{"Name", "race_id", "begin_time", "vehicle_id"},
{{"id", each List.Max([id]), type text}})
Instead of this, you want to replace List.Max with Text.Combine as follows:
= Table.Group(#"Changed Type",
{"Name", "race_id", "begin_time", "vehicle_id"},
{{"id", each Text.Combine([id], ","), type text}})
Note that if your id column is not in the text format, then this will throw an error. To fix this, insert a step before you group rows using Transform Tab > Data Type: Text to convert the type. Another options is to use List.Transform inside your Text.Combine like this:
Text.Combine(List.Transform([id], each Number.ToText(_)), ",")
Either way, you should end up with this:
An approach would be to use the Advanced Editor and change the operation done when grouping the data directly there in the code.
First, create the grouping using one of the operations available in the menu. For instance, create a column"Sum" using the Sum operation. It will give an error, but we should get the starting code to work on.
Then, open the Advanced Editor and find the code corresponding to the operation. It should be something like:
{{"Sum", each List.Sum([driver_codes]), type text}}
Change it to:
{{"driver_codes", each Text.Combine([driver_codes], ","), type text}}
I have a database with 2 tables that look like this:
content
id name
1 Cool Stuff
2 Even Better stuff
--
contentFields
id content label value
5 1 Rating Spectacular
6 1 Info Top Notch
7 2 Rating Poor
As you can see the content column of the contentFields table coincides with the id column of the content table.
I want to write a query that grabs all of the content and stores the applicable content fields with the right content, so that it comes out to this:
[
{
id: 1,
name: 'Cool Stuff',
contentFields: [
{label: 'Rating', value: 'Spectacular'},
{label: 'Info', value: 'Top Notch'}
]
},
{
id: 2,
name: 'Even Better Stuff',
contentFields: [
{label: 'Rating', value: 'Poor'}
]
}
]
I tried an inner join like this:
SELECT * FROM content INNER JOIN contentFields ON content.id = contentFields.content GROUP BY content.id
But that didn't do it.
*Note: I know that I could do this with 2 seperate queries, but I want to find out how to do it in one as that will dramatically improve performance.
What you are trying to achieve is not directly possible with SQL only.
As you have already stated yourself, you are looking for a table within a table. But MySQL does not know about such concepts, and as far as I know, other databases also don't. A result set is always like a table; every row of the result set has the same structure.
So either you let your GROUP BY content.id in place; then, for every row in the result set, MySQL will select a random row from the joined table which fits to that row's content.id (you even can't rely on that it is the same row every time).
Or you remove the GROUP BY; then you will get every row from the joined table, but that is not what you want as well.
When performance is an issue, I would probably choose the second option, adding ORDER BY content.id, and generate the JSON myself. You could do so by looping through the result set and begin a new JSON block every time the content.id changes.
Disclaimer The following is pure speculation.
I don't know anything about node.js and how it transforms result sets into JSON. But I strongly assume that you can configure its behavior; otherwise, it actually would not be of any use in most cases. So there must be a method to tell it how it should group the rows from a result set.
If I am right, you would first have to tell node.js how to group the result set and then let it process the rows from the second option above (i.e. without the GROUP BY).
I am building a music application. In my database I have an "Artist" table, related to an "Album" table, related to a "Track" table.
Each user of my application can "like" (thumbs up) or "dislike" (thumbs down) an artist/album/track. Thus, I have to create Many-to-many relationships between users and the artists/albums/tracks with an argument "vote" which can be set to 1/-1.
My question is : Would it be more appropriate to create three "Like/Dislike" tables (user_artist_like, user_album_like, user_track_like) or only one table "user_like" with three columns (artist_id, album_id, track_id) ? Knowing that I will often have to fetch all the likes of a user.
The first option is better, because putting the data in one table implies that data points in the same row are related, which is not true. Multiple tables allows you to manage the data more easily without getting confused by the rows. For instance, how would you structure a INSERT INTO statement for the single table? It couldn't use the space effectively.
Just in case anyone else reads this, you can set up a table that has a column type to handle this.
{
user_id: 7,
object_id: 12,
type: 'album',
is_liked: 1
}
{
user_id: 7,
object_id: 8,
type: 'track',
is_liked: 0 //this as 0 means disliked
}
I'm trying to output the filter results with only matching elements.
I have two tables (in the real project, which will be 5), let's say companies and projects. A company may have more than one project or may not have any.
These are the relations:
/app/models/Company.php
<?php
class Company extends Eloquent {
public function projects() {
return $this->hasMany('Project','companyID');
}
protected $table = 'companies';
}
/app/models/Project.php
<?php
class Project extends Eloquent {
public function companies() {
return $this->belongsTo('Company','companyID');
}
}
What I want to do is, I want to get results of them both but only with matching parameters.
I've tried this:
return Company::with(array('projects'=>function($query){
$query->where('id',99); //project's id is 99
}))->get();
This is the output JSON
If I change the value from 99 to 1 (there is a result with products.id of 1), it changes into this:
I only want to get the second result from the second JSON i've posted.
As you can see in the second JSON (I'm using this parser to check), all companies are loaded regardless of the project, and only the rows matched have the object projects.
There will be more 'with's and I don't know how to filter only matching elements.
I also tried having() inside closure, but it's still same:
$query->having('projects.id','=',99);
Is there a way to filter only matching results (without using a loop) which the output will only include the results having the matched projects object?
Edit: Actually, 5 tables will be filtered.
companies, projects, works, users and user_works
Let's say;
"Companies" have many projects.
"Projects" have many works
"Works" have many users, also "Users" may have more than one work (pivot table user_works).
All relations are set correctly from models.
I want to do a global searching to these.
Something like: "Bring me the user id 1's works which has company id of 5 and project id of 4", but none of the fields are mandatory.
So these are also valid for searching: "Bring me everyone's works on project id of 2", or "bring me id 2's works", or "bring me all the works starting from today", "bring me the id 1's works on project 2", "Bring me this year's works done of company id 1".
Thanks in advance
Using whereHas() is the solution on my case. It filters relation and affects the results returned in the main query.
If you have the id of the project, would it make more sense to go that route? $project = Project::find(99); and then the company variables would be accessible with $project->companies->name;
It would make more sense to rename the companies() function to company() because a project will only ever belong to one.