perform a TypeOrm find search operation for matching array of json - javascript

i have my typeorm column like this, what i want is an array of JSON object which i manage to get.
#Column({
type: 'jsonb',
array: false,
default: () => "'[]'",
nullable: false,
})
tokens!: Array<{ token: string }>;
this is how the field looks, and am fine with it, what i want is to find a document with a particular token, so i came up with the below code, but it returns an empty array.
const user = await User.find({ where: { _id: decoded._id, tokens: { token: token } } });
normally when am using mongooe i can get this working using
const user = await User.findOneBy({_id: decoded._id, "tokens.token": token,}); and this returns a particular user, with the id and token string passed.
i want help on how to find a user using the id and the token string inside in array of object, thanks.

TypeORM does not natively support queries on PostreSQL jsonb columns. Performing a query on the data in a jsonb column would require you to either issue a raw query or write your own WHERE clause in.where or .addWhere of a query builder (doc).
For reference, the jsonb query syntax documentation can be found here.

Related

Supabase - Upsert & multiple onConflict constraints

I cannot figure out how to proceed with an Upsert & "multiple" onConflict constraints. I want to push a data batch in a Supabase table.
My data array would be structured as follows:
items = [
{ date: "2023-01-26", url: "https://wwww.hello.com"},
{ date: "2023-01-26", url: "https://wwww.goodbye.com"},
...]
I would like to use the Upsert method to push this new batch in my Supabase table, unless if it already exists. To check if it already exists, I would like to use the date, and the url as onConflict criteria, if I understood well.
When I'm running this method
const { error } = await supabase
.from('items')
.upsert(items, { onConflict: ['date','url'] })
.select();
I'm having the following error:
{
code: '42P10',
details: null,
hint: null,
message: 'there is no unique or exclusion constraint matching the ON CONFLICT specification'
}
What am I missing? Where am I wrong?
You can pass more than one column in the upsert into by adding a column in a string (instead of using an array):
const { data, error } = await supabase
.from('items')
.upsert(items, { onConflict: 'date, url'} )
Postgres performs unique index inference as mentioned in https://www.postgresql.org/docs/current/sql-insert.html#SQL-ON-CONFLICT
It is necessary to have unique or indexes for this to work, as you can read in the documentation above:
INSERT into tables that lack unique indexes will not be blocked by
concurrent activity. Tables with unique indexes might block if
concurrent sessions perform actions that lock or modify rows matching
the unique index values being inserted; the details are covered in
Section 64.5. ON CONFLICT can be used to specify an alternative action
to raising a unique constraint or exclusion constraint violation
error.

MongoDB: How can populate reference, and delete element in array after based on the ID of the reference

So I have a situation where I need to delete elements in an array of reference / ObjectIds, but the delete condition will be based on a field in the reference.
For example, I have schemas like the following:
const UserSchema = new mongoose.Schema({
firstName: String,
lastName: String,
homeFeeds:[{type: Schema.Types.ObjectId, requried: true, ref: "Activity"}];
}); // User , is the referenece name
const ActivitySchema = new mongoose.Schema({
requester: {type: Schema.Types.ObjectId, requried: true, ref: "User"},
message: String,
recipient: {type: Schema.Types.ObjectId, requried: true, ref: "User"},
}) // Activity, is the reference name
Now I need to delete some of the homeFeeds for a user, and the ones that should be deleted need to be by certain requester. That'll require the homeFeeds (array of 'Activity's) field to be populated first, and then update it with the $pull operator, with a condition that the Activity requester matches a certain user.
I do not want to read the data first and do the filtering in Nodejs/backend code, since the array can be very long.
Ideally I need something like:
await User.find({_id: ID})
.populate("homeFeeds", "requester")
.updateMany({
$pull: {
homeFeeds.requester: ID
}
});
But it does not work, Id really appreciate if anyone can help me out with this?
Thanks
MongoDB doesn't support $lookup in update as of version v6.0.1.
MongoServerError: $lookup is not allowed to be used within an update.
Though, this doesn't have to do with Mongoose's populate as populate doesn't depend on $lookup and fires additional queries to get the results. Have a look at here. Therefore, even if, you could achieve what you intend, that is avoiding fetching a large array on nodejs/backend, using mongoose will do the same thing for you behind the scenes which defeats your purpose.
However you should raise an issue at Mongoose's official github page and expect a response.

TypeORM findby Child Properties of a MongoDB Document

I have a MongoDB document in the following format. I can verify that it exists in MongoDB using Compass. I'm using TypeORM to make the query, not MondoDB.
{
_id: 'some id'
user: {
details: {
email: "test#test.ch",
username: "testname"
},
status: 'active'
}
}
Is it possible to use TypeORM to find by, say, the email?
I've tried
const emailExists = await this.userRepo.findOneBy({
user: {
details: {
email: "test#test.ch"
}
}
});
but emailExists always returns null even though I can validate that it exists in MongoDB. I've tried other ways to find by email using find, findOne, and more.
How do you find a matching value of a child property, like email? Is there a better approach?
MongoDB: Query on Nested Field
To specify a query condition on fields in an embedded/nested document, use dot notation.
Example: 'field.nestedField'
When querying using dot notation:
The field and nested field must be inside quotation marks.
Applying in your code:
const emailExists = await this.userRepo.findOneBy({'user.details.email': 'test#test.ch'});
Reference:
MongoDB Official Documentation: Query on Embedded/Nested Documents
Update: Looks TypeORM not work well with MongoDB, but you can try use $match.
Example:
$match : { 'field.nestedField': nestedField }
Applying in your code:
this.userRepo.findOneBy({$match: { 'user.details.email': 'test#test.ch' }});
If not work maybe try to change TypeORM to Mongoose.
Reference:
https://github.com/typeorm/typeorm/issues/2483

compare password using sequelize fn and postgres built in crypt

i know compare password using bcrypt module is work too, but out of curiousity, i want to know if there is a away to using sequelize fn and postgres crypt?
i already try this :
const user = await Users.findOne({
where: {
username: myUsername,
password: sequelize.fn('crypt',myPassword,'password')
}
});
but not work because in the queries look like
SELECT "id", "username", "password", FROM "users" AS "Users"
WHERE "Users"."username" = 'yosiazwan' AND "Users"."password" = crypt('testing', 'password');
'password' is in single quotes when it should not. if i try that queries in pgadmin, it doesn't work too. but if i remove the 'password' single quotes, like this
SELECT "id", "username", "password", FROM "users" AS "Users"
WHERE "Users"."username" = 'yosiazwan' AND "Users"."password" = crypt('testing', password);
and that will works. is there any way to remove that single quotes in sequelize fn?
https://sequelize.org/api/v6/class/src/sequelize.js~sequelize#static-method-fn
public static fn(fn: string, args: any): fn since v2.0.0-dev3
Creates an object representing a database function. This can be used
in search queries, both in where and order parts, and as default
values in column definitions. If you want to refer to columns in your
function, you should use sequelize.col, so that the columns are
properly interpreted as columns and not a strings.
https://sequelize.org/api/v6/class/src/sequelize.js~sequelize#static-method-col
public static col(col: string): col since v2.0.0-dev3
Creates an object which represents a column in the DB, this allows
referencing another column in your query. This is often useful in
conjunction with sequelize.fn, since raw string arguments to fn will
be escaped.
Your code should look like
const user = await Users.findOne({
where: {
username: myUsername,
password: sequelize.fn('crypt',myPassword, sequelize.col('password'))
}
});

How to call a Sequelize MySQL JSON query?

I have a User model that includes a json data type. I'm using MySQL as my database, but when looking through their documentation for how to query using JSON, there appears to be nothing on MySQL.
const User = db.define("User", {
UserId: {
primaryKey: true,
type: Sequelize.INTEGER
},
colors: {
type: Sequelize.JSON,
allowNull: false
}
}
I have Users that have an id, and an array with their favorite colors in it.
UserId | colors
1 |["black, "blue"]
2 |["blue"]
3 |["black"]
I want to query for all users that have the favorite color blue. I tried querying like this,
User.findAll({ where: {colors: ["blue"]} })
and expected to be returned users 1 and 2, but this doesn't work and I have not found any sources online that shows what to do. Some stackoverflows have solutions for JSON objects, like this Sequelize, MySQL - Filtering rows in table with JSON column values, but I can't find any sources for arrays. Any solutions?
You can use sequelize.fn and sequelize.col methods to specify an SQL function call and a table column, respectively. This way you can create your own where condition.
User.findAll({
where: sequelize.where(sequelize.fn('JSON_CONTAINS', sequelize.col('colors'), sequelize.literal('blue'), sequelize.literal('$')), 1)
});
It corresponds to below mysql query:
// SELECT * FROM Users WHERE JSON_CONTAINS(colors, 'blue', '$') = 1;
The answer should be:
User.findAll({
where: sequelize.where(sequelize.fn('JSON_CONTAINS', sequelize.literal('colors'), '"blue"', '$'), 1)
});
Note:
The 2nd parameter of JSON_CONTAINS should be string.
Because the data of question is an array of string, so we need to add a " for searching keyword (e.g: "blue").

Categories

Resources