Trying to cast a column inside a where clause to search for a query against. Have a difficult time finding reliable documentation on how to do this. Any ideas?
return await User.findAndCountAll({
where: {
[Op.or]: {
'email': { [Op.iLike]: `%${query}%` },
'$id::text$': { [Op.iLike]: `%${query}%` } // id is int but needs to be string for searching
}
},
limit,
offset: page * limit,
order: [[sortBy, sortOrder.toUpperCase()]],
raw: true,
logging: console.log
});
I think this is what you searching for:
where: {
[Op.or]: [
{email: {[Op.iLike]: `%${query}%`}},
sequelize.where(
sequelize.cast(sequelize.col('User.id'), 'varchar'),
{[Op.iLike]: `%${query}%`}
),
],
},
As #leogoesger's answer didn't work for JSONB fields in Postgres, I tried this:
where: {
["data.createdAt::timestamp"]: {
[Op.lt]: "now() - interval '3 days'"
}
}
Lo and behold, it produced:
WHERE CAST(("User"."data"#>>'{createdAt}') AS TIMESTAMP) < now() - interval '3 days'
Using Sequelize 5.1.0.
This worked for me:
Notification.findOne({ where: {
[Op.and]: [
sequelize.literal("cast(notify_data as CHAR) = "+game_id),
{user: players[i].user, notify_type: type.id}
]
}});
Basically, sequelize.literal returns a string rather than a key-value pair, so I did a work around using Op.and which can take both strings and objects in its array
order: [sequelize.col('id')],
where:
sequelize.where(
sequelize.cast(sequelize.col('id'), 'varchar'),
{ [Op.iLike]: `%${filter}%` },
),
// matches all rows using id and fetching results in order (casts integer column to string)
Related
I have this SQL query:
SELECT *
FROM funds
WHERE (fund_id, created_at) > ($1, $2)
ORDER BY created_at DESC
LIMIT 5;
...that I am trying to convert into a sequelize (v6) filter object for the findAll(...) query.
I have an index for (fund_id, created_at) and I am using sqlite as the database.
My objective with the query is to be able to use keyset pagination using (fund_id, created_at).
So far this is what I have:
{
where: {
[Op.and]: [
{ fundId: { [Op.gt]: prev_fund_id } },
{ createdAt: { [Op.gt]: prev_created_at } },
],
},
limit: 5,
order: [["created_at", "DESC"]],
}
This doesn't exactly convert into the expected SQL query I mentioned above as shown by the log of the SQL query passed to my sqlite database:
SELECT `fund_id`, `name`, `description`, `created_at`, `updated_at` FROM `funds` WHERE (`fund_id` > '04e5b202-e62e-417a-b9d8-8cd5b6a1cb8f' AND `created_at` > '2023-02-13 07:38:36.683 +00:00') ORDER BY `created_at` DESC LIMIT 5;
The headache that I am running into is converting the (fund_id, created_at) > ($1, $2) expression...
I am fairly new to SQL and I believe (correct me if I am wrong) that (fund_id, created_at) is not equivalent to using the AND logical operator in SQL. Yet sequelize doesn't seem to have any operators (Op) for that expression...
How should I use sequelize to create this query?
const { Op } = require("sequelize");
Fund.findAll({
where: {
[Op.and]: [
{ fund_id: { [Op.gt]: $1 } },
{ created_at: { [Op.gt]: $2 } },
],
},
order: [["created_at", "DESC"]],
limit: 5,
})
.then(funds => {
// handle the results
})
.catch(error => {
// handle the error
});
I hope I understood well what you want to do
I want to get data from my database to work with variables.
Here is my database query:
db.progress.find({username:socket},function(err,res){
what do I get information on:
[ { _id: 61e180b54e0eea1454f8e5e6,
username: 'user',
exp: 0,
fraction: 'undf'} ]
if i send a request
db.progress.find({username:socket},{exp:1},function(err,res){
then in return I will get
[ { _id: 61e180b54e0eea1454f8e5e6, exp: 0 } ]
how do i extract only 0 from the received data. I would like to do something like this.
var findprogress = function(socket,cb){
db.progress.find({username:socket},function(err,res){
cb(res.exp,res.fraction)
})
}
findprogress(socket,function(cb){
console.log(cb.exp)//0
console.log(cb.fraction)//undf
})
but I don't know how to implement it correctly.
I recommend aggregate in this case so you can more easily manipulate your projected data. For example:
db.progress.aggregate([
{ $match: { username: socket } },
{ $project: { _id: 0, exp: 1 } }
])
This way you directly tell the query to not include the objectId, which is typically included by default.
find returns an array, so you will need to select the array element before accessing the field:
var findprogress = function(socket,cb){
db.progress.find({username:socket},function(err,res){
cb(res[0].exp,res[0].fraction)
})
}
Try to give 0 to _id:
db.progress.find({username:socket},{exp:1 , _id:0},function(err,res){
I have got a data structure:
{
field: 1,
field: 3,
field: [
{ _id: xxx , subfield: 1 },
{ _id: xxx , subfield: 1 },
]
}
I need to update a certain element in the array.
So far I can only do that by pulling out old object and pushing in a new one, but it changes the file order.
My implementation:
const product = await ProductModel.findOne({ _id: productID });
const price = product.prices.find( (price: any) => price._id == id );
if(!price) {
throw {
type: 'ProductPriceError',
code: 404,
message: `Coundn't find price with provided ID: ${id}`,
success: false,
}
}
product.prices.pull({ _id: id })
product.prices.push(Object.assign(price, payload))
await product.save()
and I wonder if there is any atomic way to implement that. Because this approach doesn't seem to be secured.
Yes, you can update a particular object in the array if you can find it.
Have a look at the positional '$' operator here.
Your current implementation using mongoose will then be somewhat like this:
await ProductModel.updateOne(
{ _id: productID, 'prices._id': id },//Finding Product with the particular price
{ $set: { 'prices.$.subField': subFieldValue } },
);
Notice the '$' symbol in prices.$.subField. MongoDB is smart enough to only update the element at the index which was found by the query.
I have a structure like this:
{
...
_id: <projectId>
en-GB: [{
_id: <entryId>,
key: 'some key',
value: 'some value',
}]
}
And I've tried updating it with Mongoose (and raw mongodb too) like this:
const result = await Project
.update({
_id: projectId,
'en-GB._id': entryId,
}, {
$set: {
'en-GB.$.key': 'g000gle!!',
},
})
.exec();
I've checked that the IDs are correct. But it doesn't update anything:
{ n: 0, nModified: 0, ok: 1 }
What am I doing wrong? Thanks
As discussed in the comments on the question, the issue is directly related to passing in a string representation of an id in the query as opposed to using an ObjectId. In general, it's good practice to treat the use of ObjectIds as the rule and the use of string representations as special exceptions (e.g. in methods like findByIdAndUpdate) in order to avoid this issue.
const { ObjectId } = require('mongodb');
.update({
_id: ObjectId(projectId),
'en-GB._id': ObjectId(entryId),
})
I have a query where I first want to match find the list of matched users and then filter the matches out from the array of external users that was passed in so that I am left with users Id's that have not been matched yet.
Here is a the match Schema:
const mongoose = require('mongoose'); // only match two users at a time.
const Schema = mongoose.Schema;
const MatchSchema = new Schema({
participants: [{
type: String, ref: 'user'
}],
blocked: {
type: Boolean,
default: false
}
});
Here is the query with explanations:
db.getCollection('match').aggregate([
{
'$match': {
'$and': [
{ participants: "599f14855e9fcf95d0fe11a7" }, // the current user.
{ participants: {'$in': [ "598461fcda5afa9e0d2a8a64","598461fcda5afa9e0d111111", "599f14855e9fcf95d0fe5555"] } } // array of external users that I want to check if the current user is matched with.
]
}
},
{
'$project': {
'participants': 1
}
},
This returns the following result:
{
"_id" : ObjectId("59c0d76e66dd407f5efe7112"),
"participants" : [
"599f14855e9fcf95d0fe11a7",
"599f14855e9fcf95d0fe5555"
]
},
{
"_id" : ObjectId("59c0d76e66dd407f5efe75ac"),
"participants" : [
"598461fcda5afa9e0d2a8a64",
"599f14855e9fcf95d0fe11a7"
]
}
what I want to do next it merge the participants array form both results into one array.
Then I want to take away the those matching items from the array of external users so that I am left with user id's that have not been matched yet.
Any help would be much appreciated!
If you don't want those results in the array, then $filter them out.
Either by building the conditions with $or ( aggregation logical version ):
var currentUser = "599f14855e9fcf95d0fe11a7",
matchingUsers = [
"598461fcda5afa9e0d2a8a64",
"598461fcda5afa9e0d111111",
"599f14855e9fcf95d0fe5555"
],
combined = [currentUser, ...matchingUsers];
db.getCollection('match').aggregate([
{ '$match': {
'participants': { '$eq': currentUser, '$in': matchingUsers }
}},
{ '$project': {
'participants': {
'$filter': {
'input': '$participants',
'as': 'p',
'cond': {
'$not': {
'$or': combined.map(c =>({ '$eq': [ c, '$$p' ] }))
}
}
}
}
}}
])
Or use $in ( again the aggregation version ) if you have MongoDB 3.4 which supports it:
db.getCollection('match').aggregate([
{ '$match': {
'participants': { '$eq': currentUser, '$in': matchingUsers }
}},
{ '$project': {
'participants': {
'$filter': {
'input': '$participants',
'as': 'p',
'cond': {
'$not': {
'$in': ['$p', combined ]
}
}
}
}
}}
])
It really does not matter. It's just the difference of using JavaScript to build the expression before the pipeline is sent or letting a supported pipeline operator do the array comparison where it is actually supported.
Note you can also write the $match a bit more efficiently by using an "implicit" form of $and, as is shown.
Also note you have a problem in your schema definition ( but not related to this particular query ). You cannot use a "ref" to another collection as String in one collection where it is going to be ObjectId ( the default for _id, and presumed of the hex values obtained ) in the other. This mismatch means .populate() or $lookup functions cannot work. So you really should correct the types.
Unrelated to this. But something you need to fix as a priority.