how to sort associated tables in sequelze? - postgresql

I want to return an associated table, but sort those items. Nothing complicated like sorting by an associated table. Just sort the associated elements.
public static async findWith(finder: any): Promise<Race | null> {
const race = await Race.findOne({
where: finder,
include: [
{
model: Rocket,
order: ['id', 'desc']
}
]
})
return race
}
I tried a few options,
order: ['id', 'desc']
order: [['id', 'desc']]
order: [[Rocket, 'id', 'desc']]. // nested
which are all accepted without error, but the sorting isn't applied.
research:
https://github.com/sequelize/sequelize/issues/4553
https://sequelize.org/docs/v6/core-concepts/assocs/
other question
I'm using sequelize-typescript with v6 and postgres.

It is mentioned in sequelize documentation that if you want to apply ORDER clauses to eager loaded models, you must use the top level order option. Therefore, you should write it outside the include option like this
const race = await Race.findOne({
where: finder,
include: [
{
model: Rocket
}
],
order: [[Rocket, 'id', 'desc']]
})

Related

Prisma Typescript where clause inside include?

I am trying to query the database (Postgres) through Prisma. My query is
const products = await prisma.products.findMany({
where: { category: ProductsCategoryEnum[category] },
include: {
vehicles: {
include: {
manufacturers: { name: { in: { manufacturers.map(item => `"${item}"`) } } },
},
},
},
});
The error message is
Type '{ name: { in: { manufacturers: string; "": any; }; }; }' is not assignable to type 'boolean | manufacturersArgs'.
Object literal may only specify known properties, and 'name' does not exist in type 'manufacturersArgs'.ts(2322)
Manufacturers have the field name and it is unique; I am not sure why this is not working or how I can update this code to be able to query the database. It is like I should cast the values into Prisma arguments.
The TypeScript error is pretty self-explanatory: the name property does not exist in manufacturersArgs. The emitted Prisma Client does a great job of telling you what properties do and do not exist when filtering.
If you are trying to perform a nested filter, you need to use select instead of include.
Documentation: https://www.prisma.io/docs/concepts/components/prisma-client/relation-queries#filter-a-list-of-relations
Your query is going to look something like this:
const products = await prisma.products.findMany({
where: { category: ProductsCategoryEnum[category] },
select: {
// also need to select any other fields you need here
vehicles: {
// Updated this
select: { manufacturers: true },
// Updated this to add an explicit "where" clause
where: {
manufacturers: { name: { in: { manufacturers.map(item => `"${item}"`) } } },
},
},
},
});
The final code ultimately depends on your Prisma schema. If you are using an editor like VS Code, it should provide Intellisense into the Prisma Client's TypeScript definitions. You can use that to navigate the full Prisma Client and construct your query based on exactly what is and is not available. In VS Code, hold control [Windows] or command [macOS] and click on findMany in prisma.products.findMany. This lets you browse the full Prisma Client and construct your query!
The in keyword isn't working for me. I use hasSome to find items in an array. hasEvery is also available depending what the requirements are.
hasSome: manufacturers.map(item => `"${item}"`),
See https://www.prisma.io/docs/reference/api-reference/prisma-client-reference#scalar-list-filters

How to target a field in Prisma and get a flat array of values rather than an array of objects

I just started using Primsa 2 so I am still a noob at this but all I am trying to do is create a flat array of strings(Array<number>) based on the values I get from a specific field. Right now when I target that field it gives me an array of objects like this: userIds: [{ issueId: 1, userId: 1 }]
All I want is the value I get from the userId key and the array to return like this userIds: [ 1 ]. I was able to fix this with some formatting code after the query which was done like so:
const issues = project.issues.map(issue => ({ ...issue, userIds: [...issue.userIds.map((id) => id.userId)] }))
const _project = { ...project, issues }
However, this doesn't seem like the most optimal solution. If this is the only way that is fine but I assume with the power that Prisma has for querying, this is something I can do just in the query alone?
For reference, my query currently looks like this:
const project = await prisma.project.findFirst({
where: { id: req.currentUser.projectId },
include: { users: true, issues: { include: { userIds: true } } },
})
Thanks in advance!
Can you show your schema? Perhaps you can model the relation differently. However, unless if you provide a field, userIds, that is a flat array and not a field of a an other relation it will be returned as a list of objects as you have already.

PG-Promise - "Property doesn't exist" error with skip function

I am having trouble figuring out how to utilize skip to skip undefined/null values. I keep getting Error: Property 'vehicle_id' doesn't exist. Is skip within column set and skip of upsertReplaceQuery() somehow conflicting with each other? How can I get it to work?
const vehicleColumnSet = new pgp.helpers.ColumnSet(
[
{ name: 'user_id' },
{
name: 'vehicle_id',
skip: (c) => !c.exists,
},
{ name: 'model_id', def: null },
],
{ table: 'vehicle' }
);
const upsertReplaceQuery = (data, columnSet, conflictField) => {
return `${pgp.helpers.insert(
data,
columnSet
)} ON CONFLICT(${conflictField}) DO UPDATE SET ${columnSet.assignColumns({
from: 'EXCLUDED',
skip: conflictField,
})}`;
};
const vehicleUpsertQuery = upsertReplaceQuery(
{
user_id,
model_id: vehicle_model,
},
vehicleColumnSet,
'user_id'
);
await task.none(vehicleUpsertQuery);
PostgreSQL has no support for any skip logic within its multi-row insert syntax.
And pg-promise documentation also tells you within skip description:
An override for skipping columns dynamically.
Used by methods update (for a single object) and sets, ignored by methods insert and values.
It is also ignored when conditional flag cnd is set.
At most, you can add such logic against a single-row insert, as shown here.

MongoDB performance: $and vs. single object with multiple keys

I have an internal service that does some operations on an order, it has a built-in required filter, and the service users can pass additional filter.
Two approaches to achieve the same thing:
A) Using $and:
async function getOrders ({ optionalFilter = {} }) {
const baseFilter = { amount: { $gt: 10 } };
const mergedFilter = { $and: [baseFilter, optionalFilter] };
return await Order.find(mergedFilter);
}
B) Merging all in the same object
async function getOrders ({ optionalFilter = {} }) {
const baseFilter = { amount: { $gt: 10 } };
const mergedFilter = { ...baseFilter, ...optionalFilter };
return await Order.find(mergedFilter);
}
I prefer the first approach because it allows me to do the following without overwriting the $gt: 10 rule while the second would break the code by overwriting the internal rule.
getOrders({ optionalFilter: { amount: { $lt: 50 } } });
My question is, is there any advantage (performance or otherwise) of choosing one over the other?
My question is, is there any advantage (performance or otherwise) of choosing one over the other?
Short answer: No. If you are not using (compound) indexes
Long Answer: Okay, let's test this up, right?
So let's take a collection of ~100k documents, and un-indexed array field:
{asset_class: "COMMDTY"}
with {$and: [{item_subclass: "Herb", asset_class: "COMMDTY"}]}
without {item_subclass: "Herb", asset_class: "COMMDTY"}
Okay, there is 114ms difference between using $and and without. But does it means to stop you using $and and avoid it? Of course, not. But as much field have added, the more slower Mongo will become. But this whole picture changes, when I add an already indexed field to a query.
{expansion: "BFA", asset_class: "COMMDTY"}
So, if you add more fields via your mergedFilter then make sure that your index (if you are using them) can be used, because as for compound index field order is very meaningful. So the query: {asset_class: "COMMDTY", expansion: "BFA" } will goes already in:

Sequelize query where record does not exist in related table or does exist in related table with condition

I'm trying to write a sequelize query which includes a relation from different table with hasMany relation. I want my query to return if some column in related table has matches my condition or there is not related row in the related table with foreign key from my main table.
Think about two different models, main one, which is folders, has id, name etc. columns and related table, which is folderOwners has id, folderId and groupId columns which shows which folders is owned by which groups. So, folders can have multiple owner groups.
include: [{
association: "owners",
required: true,
where: {
groupId: {[Op.in]: userGroups.map(group => group.id)}
}
}]
I can get the folders which owned by one of the groups that user is in but I want to get all folders if there is no row in related table, which means folder is not owned by anyone.
I've tried to change required to false and use Op.or for where like below
required: true,
where: {
[Op.or]: [
{groupId: {[Op.in]: userGroups.map(group => group.id)}},
{groupId: {[Op.eq]: null}}
],
}
So, are there any ways to achieve what I want?
If I understood correctly your problem, try this code :
Folder.findAll({include: [{model: Group, required: false}])
it will get all the folders with and without Groups
You can reference to nested model's column from parent model's "where" object using syntax like this: "$AssociatedTableName.columnName$"
Folder.findAll({
where: {
[Op.or]: [
{ '$Group.id$': null },
{
'$Group.id$': {
[Op.in]: [ids],
},
},
],
},
include: [
{
model: Group,
as: 'Group',
required: false,
},
],
});