I got the following data model: https://imgur.com/a/AwwpW9F
Basically, A User can belong to many Projects, and a Project can have many Users and I'm tying that together through a join table called UserProjects
With a raw SQL query I can go
SELECT "user".email, project.name FROM "user"
JOIN userprojects ON userprojects.user_id = "user".id
JOIN project ON project.id = userprojects.project_id
Which gives me
email(On User table) name(On Project table)
first#email.com Project X
first#email.com Project Y
second#email Project Y
How would I structure this query with Objection ORM? Perhaps I can just do a raw query straight? Something like
User.query().raw(SELECT "user".email, project.name FROM "user"
JOIN userprojects ON userprojects.user_id = "user".id
JOIN project ON project.id = userprojects.project_id)
?
instead of doing all the stuff by yourself, Objection.js can do it for you. You can just declare a ManyToManyRelation.
static relationMappings = {
projects: {
relation: Model.ManyToManyRelation,
modelClass: Project, // imported Objection class of "Project"
join: {
from: 'user.id',
through: {
from: 'userprojects.user_id',
to: 'userprojects.project_id'
},
to: 'project.id'
}
}
}
Then you can just get the projects of a User using eager loading:
User.query().eager('projects').findById(userId)
And you will get something like:
User {
id: 3,
firstname: 'firstname',
lastname: 'lastname',
email: 'email',
projects: [
{id: 1,
name: 'name1'},
{id: 2,
name: 'name2'},
]
}
2020 Update:
Since version 2 of Objection.js, eager method has been renamed as withGraphFetched:
User.query().withGraphFetched('projects').findById(userId)
Nvm, found a solution
/close
JK,
Here's what worked for me if anyone else would run into the same issue:
return User.query().where("user_id", parent.id)
.join('userprojects', 'user.id', '=', 'userprojects.user_id')
.join('project', 'project.id', '=', 'userprojects.project_id')
.select('user.id', 'userprojects.project_id', 'project.name')
Related
How can I upsert many fields in prisma ORM with one query?
I don't want to use upsert fields one by one. Can I upsert all of them with one query?
You can't do it right now in Prisma.
Most efficient way if you need to handle lots of data would probably be something like that:
prisma.$transaction([
prisma.posts.deleteMany({ where: { userId: 1 } }),
prisma.posts.createMany({
{ id: 1, title: 'first', userId: 1 },
{ id: 2, title: 'second', userId: 1 },
{ id: 3, title: 'third', userId: 1 },
}),
]);
So you delete existing records and then recreate them again inside of a transaction.
Depending on the database (and schema) you use, Prisma supports an optional boolean within a createMany call: skipDuplicates, see https://www.prisma.io/docs/reference/api-reference/prisma-client-reference#createmany
Do not insert records with unique fields or ID fields that already exist. Only supported by databases that support ON CONFLICT DO NOTHING.
My models:
Recipe (id, name)
Ingredient (id, name)
Recipe_Ingredient (recipeId, ingredientId, quantity)
My associations:
Recipe.belongsToMany(Ingredient, { through: Recipe_Ingredient })
Ingredient.belongsToMany(Recipe, { through: Recipe_Ingredient })
My problem:
How can I create a Recipe with some Ingredients and the quantities attached to them?
I tried:
Recipe.create({
name: 'Pizza',
ingredients:[
{
name: 'mozarella',
recipe_ingredients: {
quantity: 5
}
}
]
}, {
include:[Ingredient]
})
Records are created for Recipe, Ingredient and the Recipe_Ingredient. The only problem is that the value of the quantity is not collected from the data source.
It was not possible to do this in the past, but in October 23, 2018 this was fixed in sequelize PR #10050.
As of today (2018-10-24) the fix is not released yet, but as soon as v5.0.0-beta14 comes out, you'll be able to do the following:
Recipe.create({
name: 'Pizza',
ingredients: [
{
name: 'mozarella',
recipe_ingredient: {
quantity: 5
}
}
]
}, {
include: Ingredient
})
Also, note that the correct usage is recipe_ingredient: in the singular form, not in the plural form as you tried in your question. This makes sense, because for a given Ingredient, associated with a given Recipe, there is only one Recipe_Ingredient involved, always.
If you do not want to wait for v5.0.0-beta14 (although it will probably be released very soon), you can install it directly from github's master branch as follows:
npm install --save https://github.com/sequelize/sequelize/tarball/master
A solution I found, inspired by answers of pedro around here (How do I ORM additional columns on a join table in sequelize?) and there is given by a change of perspective.
receipe (name:string)
ingredient (quantity:int)
type (name: string)
receipe.hasMany(ingredient, {as:'ingredients'} )
ingredient.belongsTo(type)
and then I can consume data like this:
receipe.create({
name: 'Pizza',
ingredients:[
{
quantity: 5,
type: {
name: 'ingredient 1'
}
}, {
quantity: 6,
type: {
name: 'ingredient 2'
}
} {
quantity: 5,
type_id: 1
}]
}, {
include:[{
model; ingredient,
as: 'ingredients',
include:[{
model: type
}]
}]
})
It has some drawbacks but it is good enough for me.
One problem can be that if you add two items of the same new type, you will get a unique key violation (as types are unique and sequelize will not try to search if the type exists before trying to create it).
Another problem is that if you specify just the type_id in the data, it will not actually return the type refereed by that in the result.
I'm writing a node.js app that uses the pg package for accessing a PostgreSQL database. The issue I'm running into is that if I do a query like this:
select * from posts p inner join blogs b on b.id = p.blog_id
When I get the results, they're all in the same namespace, so any field repeated in the blogs table will overwrite those in the posts table.
My question is, what's the best way of binding these results to objects?
Ideally, I'd like a result like:
{
id: 1,
name: 'A post name',
published_at: (some date object),
blog_id: 1,
b: {
id: 1,
name: 'A blog name'
}
}
But I'm open to any convenient solution short of adding an alias for every column manually.
http://www.postgresql.org/docs/9.3/static/functions-json.html
http://www.postgresql.org/docs/9.4/static/functions-aggregate.html
You may want to look at the json features of Postgres. If I'm understanding you right, and without a test database something like this may be close to what you're looking for:
SELECT
p.*, /* Select all the post fields */
row_to_json(blogs.*) as b /* Use the row_to_json function on the blogs results */
FROM
posts p
INNER JOIN
blogs ON (blogs.id=p.blog_id); /* Join blogs on the proper fields */
Returns:
{
id: 3,
name: 'test',
published_at: 2015-10-08,
blog_id: 2,
b: {
id:2,
name:"test 2"
}
}
Here's a great tutorial on them:
http://bender.io/2013/09/22/returning-hierarchical-data-in-a-single-sql-query/
If you change your query to
'SELECT * FROM posts, blogs WHERE posts.id = blogs.id;'
you should have your column names prefixed with either 'posts' or 'blogs'
If you want a nested result like above, you'll have to run some manual processing.
res.map(d => {
return {
id: d.posts_id
b : {
id: d.blogs_id
}
};
});
We have an application where we're storing two types of documents in a Mongo database:
contacts, which basically represent people
filters, which are essentially a stored MongoDB query that represents a "saved search" for a user.
Here's a simplified version of what the data models would look like:
contacts: [
{ id: 1, name: 'Phil', age: 40 },
{ id: 2, name: 'Bob', age: 34 }
]
filters: [
{ query: { name: 'Phil' } }
{ query: { age: { >: 30 } } }
]
Given a filter, it's relatively easy to list all contacts that match that filter:
db.contacts.find(filter.query);
What's harder is finding all filters that match a certain contact. Right now we have something like the following:
matchedFilters = []
_.each(filters, function(filter) {
if (db.contacts.find(_.extend(filter.query, {id: contact_id}).length > 0) {
matchedFilters.push(filter.id)
}
});
Essentially, we need to ask mongo about each filter individually. This results in a huge amount of queries to Mongo.
At the time that we are evaluating this query, we have all the relevant information about the contact we are trying to find. Is there any way to apply the Mongo query syntax to an in-memory Javascript object without needing to ask Mongo about it?
Alternatively, is there a way to ask Mongo to conduct a large number of queries in a single round trip?
Have a look at sift.js. I think, it's exactly what you're looking for.
And here is a blog post about it.
I am currently using StrongLoop as my API backend server and Mongodb as data storage engine.
Let's say there is a collection called article. It has two fields title, and content. And there are two frontend pages to display a list of articles and view a single article.
Obviously the data list page only need title field and the view page need both. Currently the GET method of StrongLoop API return all fields including content. It cost extra traffic. Is there any way that can just return specific field?
Mongodb support projection in find() method for this. How can I do the same thing by StrongLoop?
Have you taken a look at the filters offered. http://docs.strongloop.com/display/LB/Querying+models
Query for NodeAPI:
server.models.Student.findOne({where: {RFID: id},fields: {id: true,schoolId: true,classId: true}}, function (err, data) {
if (err)
callback(err);
else {
callback();
}
})
Query for RestAPI :
$http.get('http://localhost:3000/api/services?filter[fields][id]=true&filter[fields][make]=true&filter[fields][model]=true')
.then(function (response) {
}, function (error) {
});
You can use fields projections,
Sample Record:
{ name: 'Something', title: 'mr', description: 'some desc', patient: { name: 'Asvf', age: 20, address: { street: 1 }}}
First Level Projection:
model.find({ fields: { name: 1, description: 1, title: 0 } })
and I think Strong loop is not yet supporting for second-level object filter, does anyone know how to filter second-level object properties or is yet to implement?.
Second Level Projection: (Need help here)
Ex: 2
model.find({ fields: { name: 1, 'patient.name': 1, 'patient.age': 1, 'patient.address': 0 } })
// Which results { name } only