sequelize, query property on array of objects - postgresql

I have looked extensively for an answer but could not find a simple solution.
I have a table that contains a column subscriptionHistory
The data can look like so:
[
{
"fromDate": "2023-01-24T10:11:57.150Z",
"userSubscribedToo": "EuuQ13"
},
{
"fromDate": "2022-01-24T10:11:57.150Z",
"tillDate": "2022-02-24T22:59:59.999Z",
"userSubscribedToo": "a4ufoAB"
}
]
I'm trying to find the records of the subscriptions.
In Mongo we do
'subscriptionHistory.$.userSubscribedToo' = 'a4ufoAB'
Nice and easy.
I'm using PostgreSQL and Sequelize,
The following doesn't work.
const totalEarnings = await SubscriptionToken.count({
where: {
'subscriptionHistory.$.userSubscribedToo': user.id,
},
});
Neither do any direct queries
SELECT *
FROM vegiano_dev."subscription-tokens"
WHERE "subscriptionHistory"->>'userSubscribedToo' = 'a4ufoAB'
--WHERE "subscriptionHistory" #> '{"userSubscribedToo": "a4ufoAB"}'
Not sure where to go now :-/

You can use a JSON path condition with the ## (exists) operator:
select *
from vegiano_dev."subscription-tokens"
where "subscriptionHistory" ## '$[*].userSubscribedToo == "a4ufoAB"'
The #> will work as welll, but because subscriptionHistory is an array, you need to use an array with that operator:
where "subscriptionHistory" #> '[{"userSubscribedToo": "a4ufoAB"}]'
This assumes that subscriptionHistory is defined as jsonb which it should be. If it's not, you need to cast it: "subscriptionHistory"::jsonb

Related

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.

POSTGRES check if a provided value is present in the column of type array

I am trying to check whether a value if present in the column, which is of type array(column_name text[]).
As a server i am using hapi and trying to check the same from hapi through query.
Query which i have written is(query is not working):
where: { column_name: { $in: { provided_value} }}
The column contains the values as:
{1234, 3456}
The values are of type text.
Can someone please help me to identify the issue.
Thanks in advance.
Sequelize does not support this use of ANY, they seem to only support its use like IN.
Instead, you should try the contains operator (#>):
import {Op} from "sequelize";
MyModel.findAll({
where: {
column_name: {
[Op.contains]: [provided_value]
}
}
});
This will generate something like
SELECT * FROM "MyModel" WHERE column_name #> '{"provided_value"}';

How to find the data inside of array using mongoose

I have a data like below in MongoDB.
const A = { uid: '1234',
works: [
{ name: 'car',
item:['tire','wheel']
},
{ name: 'ship',
item:['tire','wheel']
}
]
My goal is to find whether the name duplicated exists or not.
In conclusion, I want to get only the names.
So 'res.send(result)' gives me like '[car, ship]'.
But the code below doesn't work. How can I make that function? Thank you so much.
const workName = await User.findOne({
uid: userID, works:{$in:['name']}
});
The easy way is to find the aggregate of name and check if the count is greater than one. Since it is inside the the array we need to unwind it.
The below query works, to detect if a sub document contain duplicates for each document.
db.getCollection('collection_name').aggregate([{"$unwind":"$works"} ,{"$group":{"_id":{"name":"$works.name","uid":"$uid"},"count":{"$sum":1}}},{"$match":{"count":{"$gte":2}}}])
if you want to find in all the documents remove uid from _id of group.

TypeORM PostgreSQL select where JSON field equals some value

Goal: write a select query that returns all rows where state equals "florida".
Entity column:
#Column({ type: 'json'})
public address: Address;
Sample column value:
{"city": "miami", "state": "florida"}
Example query (doesn't work):
getManager().getRepository(User)
.createQueryBuilder('user')
.select()
.where('user.address.state =:state', {state: "florida"})
Is this functionality currently supported in typeorm? If so, how would I need to modify my where clause to return the correct rows?
Another possible solution (raw SQL can not be injected with this):
.where('user.address ::jsonb #> :address', {
address: {
state: query.location
}
})
With this, TypeORM will produce an SQL query ending with
WHERE user.address ::jsonb #> $1
and the query will be given e.g.
{ state: 'florida' }
as a query parameter to replace the right value ($1) in the query.
Sources: Mainly the original question + answer (thank you!) + own testing + https://www.postgresql.org/docs/9.4/functions-json.html
Got it working.
Correct syntax:
.where(`user.address ::jsonb #> \'{"state":"${query.location}"}\'`)
It works for me:
.getRepository(User)
.createQueryBuilder('user')
.where(`user.address->>'state' = :state`, {state: "florida"})
return getRepository(User)
.createQueryBuilder()
.where('address #> :address', {
address: { state: "florida" },
})
.getMany();
try this:
const users = await getManager()
.getRepository(UserEntity)
.createQueryBuilder(`user`)
.where("address->>'state' = :state")
.setParameters({ state })
.getMany();
.where(`user.address -> '$.state' = :state`, {state: "florida"})
This works for me. I just use TypeORM like function.
.find({
where: {
address: Like(`%${add what to search for here}%`),
},
});

Sequelize: where query string is in array of strings postgresql

I am trying to perform a query in sequelize where I want to get only users that have the correct role. Roles are stored as an array of strings. For example ['student'] or ['school_owner', 'admin'].
In this particular case, I'm actually trying to get a school and include the school owners for that school. The failing relevant query is
const ownerQuery: { [key: string]: any } = {};
ownerQuery.roles = {$in: ["{school_owner}"]};
School
.findById(req.params.id,{include: [{ model: User, where: ownerQuery }]})
.then((school: School | null) => {
if (school === null) {
res.status(404).json({message: "Not Found"})
} else {
res.json(school)
}
}, (error) => next(error))
sequelize is storing the array values as something like {school_owner, admin}. The documentation says that I can use the following instead for my $in query
ownerQuery.roles = {$in: ["school_owner"]};
Which removes the {} but it gives me a Array value must start with "{" or dimension information.' error.
In the first example, the query doesn't fail, but it doesn't work like an $in query either. I have to match the contents of roles exactly. For example, if a user has both admin and school_owner roles I have to say
ownerQuery.roles = {$in: ["{school_owner, admin}"]};
What's the correct way to perform an $in query so that I can match all users that have a specific roles?
The correct way to implement this functionality is to do the following
ownerQuery.roles = { $contains: ["school_owner"] };
This will return all users that have a role school_owner in their array of roles