TypeORM findby Child Properties of a MongoDB Document - javascript

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

Related

insert id into type array mongodb

My mongodb collection login is structured as so:
email: "John.doe#gmail.com"
password: "password"
full_name: "John Doe"
list_of_docs_bought: Array
0: "g81h8"
1: "fursr"
now, in my code, what I want to do is insert a new id into the list_of_docs_bought array. My code is as follows:
let collection = database.collection('login')
let doc = collection.updateOne({ email: req.session.username }, {$set: { list_of_docs_bought: '2xx729' }})
however, this isn't going to work because I need to essentially insert a new id into there, not update it. But if I use .insert(), I am not sure if that is going to work because it will insert a totally new record instead of just into the array. Can anyone offer some help?
You can use upsert which does exactly what you need.
Explanation below is taken from the official docs.
Creates a new document if no documents match the filter. For more details see upsert behavior.
Updates a single document that matches the filter.
So you would need to change your code to that:
let doc = collection.updateOne({ email: req.session.username }, {$push: { list_of_docs_bought: '2xx729' }}, { upsert: true })
Edit: You need to use the $push operator in order to add an element in an array. The $set operator will just overwrite it.

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'))
}
});

perform a TypeOrm find search operation for matching array of json

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.

How to filter an array of subdocuments by two fields in each subdocument

I am attempting to add a help request system which allows the requestor to make only one request for help on each topic from an expert. If the expert lists multiple topics which they can help, I want to limit each requestor to one help request per topic per expert.
I am using node.js and mongoose.js with a self-hosted mongodb instance
I have tried using the $and operator to find the ._id of the expert as long as they don't already have an existing request from the same requestor on the same topic. It works for one update but after the experts document has a subdocument inserted with either the topic_id or the requestor_id the filter is applied and no expert is returned.
// Schema
ExpertSchema = new mongoose.Schema({
expert_id: String,
helpRequests: [
requestor_id: String,
topic_id: String
]
});
//query
const query = {
$and:[
{expert_id: req.body.expert_id},
{'helpRequests.requestor_id': {$ne: req.body.requestor_id}},
{'helpRequests.topic_id': {$ne: req.body.topic_id}}
]
};
// desired update
const update = {
$push: {
helpRequests: {
requestor_id: req.body.requestor_id,
topic_id: req.body.topic_id
}
}
Expert.findOneAndUpdate(query, update, {new: true}, (err, expert) =>{
// handle return or error...
});
The reason you are not getting any expert is condition inside your query.
Results always returned based on the condition of your query if your condition inside query get satisfied you will get your result as simple as that.
Your query
{'helpRequests.requestor_id': {$ne: req.body.requestor_id}},
{'helpRequests.topic_id': {$ne: req.body.topic_id}}
you will get your expert only if requestor_id and topic_id is not exists inside helpRequests array. thats you are querying for.
Solution
As per you schema if helpRequests contains only requestor_id and topic_id then you can achieve what you desire by below query.
Expert.findOneAndUpdate(
{
expert_id: req.body.expert_id,
}, {
$addToSet: {
helpRequests: {
requestor_id: req.body.requestor_id,
topic_id: req.body.topic_id
}
}
}, { returnNewDocument: true });

MongoDB / Mongoose: MarkModified a nested object

Unfortunately I don't have a record I can test this on, but I can't find any information on this anywhere.
Say I have a document like this:
{
email: {
type: 'Gmail',
data: {//freeform data},
}
}
I want to update doc.email.data. I need to use markModified() or else the data won't save correctly.
Do I mark modified like this?
doc.email.data = newData;
doc.markModified('email.data');
doc.save();
Or do I just do markModified('email') and Mongoose will work out the rest?
You need to provide the full path the modified object field, so it should be:
doc.markModified('email.data');

Categories

Resources