How to use sequalize.literal IF statement in node js - javascript

I need to use sequalize.literal in my node js code.
What I need to do is use an If else statement inside that sequalize literal,
Are there any references for this?
I tried in the below way, but node js returning that syntax is wrong. Can someone helop me to correct the syntax?
sequelize.literal('if(userId is not null, yes,no) as status')

I think what you really want is to use a MySQL case statement inside of a sequelize subquery.
The relevant MySQL docs are for cases statements can be found here, and the sequelize docs for sub queries can are here.
Here's an example similar to the query in the original question.
let {
Sequelize,
DataTypes,
} = require('sequelize')
async function run () {
let sequelize = new Sequelize(process.env.DB_NAME, process.env.DB_USER, process.env.DB_PASSWORD, {
host: 'localhost',
dialect: 'mysql',
logging: console.log
})
let Comment = sequelize.define('comment', {
userId: DataTypes.INTEGER,
comment: DataTypes.STRING
})
await sequelize.sync({ force: true })
await Comment.bulkCreate([{
comment: 'Hello'
}, {
userId: 42,
comment: 'This is it.'
}, {
userId: 128,
comment: 'Breakfast of the day.'
}])
let comments = await Comment.findAll({
attributes: [
'id',
'comment',
[ sequelize.literal('(case when userId is not null then "yes" else "no" end)'), 'status' ]
]
})
console.log(JSON.stringify(comments, null, 2))
await sequelize.close()
}
run()
This outputs
[
{
"id": 1,
"comment": "Hello",
"status": "no"
},
{
"id": 2,
"comment": "This is it.",
"status": "yes"
},
{
"id": 3,
"comment": "Breakfast of the day.",
"status": "yes"
}
]

Related

Match not working in MongoDB. Match is returning an empty array

I'm trying to create an aggregation pipeline. The beginning of the code works okay. But when comes to the $match, the code returns nothing. Here is my code:
var userId = req.params.UserId
const measure = await Measure.aggregate([
{
$project: {
user: 1, creationDate: 1, WaterConsumption: 1
}
},
{
$match: {
user: userId
}
},
{
$group: {
_id: {
$dayOfMonth: "$creationDate"
},
waterConsumption: {$sum : "$WaterConsumption"}
}
}
]);
return res.json({measure})
My data is:
{
"measures": [
{
"creationDate": "2021-03-19T10:25:05.674Z",
"_id": "605870bffa87a605bf2a983a",
"avgPower": 8241,
"WaterConsumption": 22,
"avgTemperature": 45,
"shower": "5fb56ce7734b7e04b9c97c9b",
"user": "5f6cb0496a8c5a0deaa1a746"
},
{
"creationDate": "2021-03-19T10:25:05.674Z",
"_id": "605870d9fa87a605bf2a983b",
"avgPower": 8241,
"WaterConsumption": 22,
"avgTemperature": 45,
"shower": "5fb56ce7734b7e04b9c97c9b",
"user": "5f6cb0496a8c5a0deaa1a746"
},
{
"creationDate": "2021-03-17T10:25:05.674Z",
"_id": "605870ebfa87a605bf2a983c",
"avgPower": 4300,
"WaterConsumption": 32,
"avgTemperature": 28,
"shower": "5fb56d04734b7e04b9c97c9c",
"user": "5f6cb0496a8c5a0deaa1a746",
}...
]
The code runs perfect till it reaches the $match. If I console my userId it is a string with the user value "5f6cb0496a8c5a0deaa1a746". I don't know why $match is not working. The $group is working perfectly.
I tried to swap the match to $match:{user: req.params.UserId} but the code keeps returning an empty array.
You are trying to match string with ObjectID that's why your $match is not working.
ObjectId
Working demo with ObjectID - https://mongoplayground.net/p/Oz95gFwvp9X
const mongodb = require('mongodb');
const ObjectID = mongodb.ObjectID;
const userId = ObjectID(req.params.UserId); // convert your userid to ObjctedID format
Eg - userId - 5f6cb0496a8c5a0deaa1a746 will be converted to ObjectId("5f6cb0496a8c5a0deaa1a746")
Not working with string - https://mongoplayground.net/p/5PN8WeXt2zc

Mongo text index on populated fields

Im just learning indexing with Mongoose/MongoDB and I dont know why this isnt working.
this is my schema
const timeSchema = new mongoose.Schema({
actionId:{
type:String,
required:true
},
start: {
type: Date
},
end: {
type: Date
},
user:{type : mongoose.Schema.Types.ObjectId, ref : 'User'},
task:{type : mongoose.Schema.Types.ObjectId, ref : 'Task'},
pausedSeconds:{
type: Number,
default: 0
}
});
const Time = mongoose.model('Time', timeSchema)
i want to have a text index in two populated fields user and task, i created the index this way
timeSchema.index({"user.name":"text","task.taskName":"text"})
Here is an example of the documents
{
"pausedSeconds": 18,
"_id": "5db1dde8d5bc93526c26fa38",
"actionId": "5feaebcf-6b90-45be-8104-452d643472a0",
"user": {
"_id": "5d4af77e4b6cbf3dd8c5f3ac",
"name": "admin"
},
"task": {
"_id": "5d4aff2f61ad755154b8a1c6",
"taskName": "task 1 updated!"
},
"start": "2019-10-24T17:22:48.000Z",
"end": "2019-10-24T17:30:00.000Z"
},
I have one issue and one question
The issue is:
What im trying to do is get all the documents that have "task 1 updated" (for task.taskName) or
"admin" (for user.name) doing it this way
Time.find({ '$text': { '$search': "admin" } })
Time.find({ '$text': { '$search': "task 1 updated" } })
but it doesnt seem to work
The question is:
If I want to do a text search for the fields start,end being a Date type or for the field pausedSeconds being a Number type what should I do?
Thanks in advance
In your query, you aren't specifying what property to search on. Do this: Time.find({taskName: { '$text': { '$search': "admin" }}}).
Also, I'm not sure if you're just not showing all the code or if you're actually doing your query wrong, but it should be written like this:
Time.find({taskName: { '$text': { '$search': "admin" }}}).exec(function(err, times) {
if(err) return console.log(err);
console.log(times);
});

trying to map and than filter through mongoose collection doesn't work as expected

I am finishing a my personal social network/e-commerce hybrid project, i try to map through the reviews array and than filter the likes array which is empty and should carry on reading the code, but somehow it gives me 'User has already liked this' error, which is supposed to fire if user has liked the review posted to this product, but the likes arrays are empty.
I have lost count to what have i tried fixing this, since i am fairly a new dev, I wasn't able to find a solution to this, I won't be surprised if it's really a very basic mistake :D
This is one of the products. I have created some reviews, and try to like them
{
"_id": "5c937d124b068106100f4f7e",
"name": "Assasin's Creed 3 Remastered",
"developer": "Ubisoft",
"image": "https://ubistatic19-a.akamaihd.net/ubicomstatic/en-us/global/game-info/ac3r_naked_boxshot_tablet_343557.jpg",
"image2": "http://ngerandom.com/wp-content/uploads/2019/02/Assassins-creed-3-test-bild-7.jpg",
"genre": "Action-adventure, Stealth",
"trailer": "https://www.youtube.com/watch?v=9IupDCUCFK4",
"release": "29.03.2019",
"platforms": "PC, PS4, Xbox One",
"__v": 6,
"reviews": [
{
"_id": "5c9b5bf4e9e15b17008a69e8",
"text": "good comment",
"user": "5c8acf4b62b2590f8c9221ce",
"likes": [],
"dislikes": [],
"comments": [],
"date": "2019-03-27T11:18:12.846Z"
},
{
"likes": [],
"dislikes": [],
"comments": [],
"date": "2019-03-27T08:23:27.959Z",
"_id": "5c9b32ff09a9342188ddc35a",
"text": "A very good game once more",
"user": "5c8acf4b62b2590f8c9221ce"
}
]
}
This is the code that has to like it
router.post(
"/like/:product_id/:id",
passport.authenticate("jwt", { session: false }),
(req, res) => {
Profile.findOne({ user: req.user.id }).then(profile => {
Product.findById(req.params.product_id)
.then(product => {
if (
product.reviews.map(
review =>
review.likes.filter(
like => like.user.toString() === req.user.id
).length > 0
)
// product.likes.filter(like => like.user.toString() === req.user.id)
// .length > 0
) {
console.log(product.reviews.toString());
return res
.status(400)
.json({ alreadyliked: "User already liked this product" });
This is the error that i get
{
"alreadyliked": "User already liked this product"
}
I have been trying to fix this last 4 hours, I won't be able to thank you enough if you'll try to help me fix this
Your problem is the if that is always true.
Your .map + filter are creating an array of boolean.
if([false, false, false]) is always true (also if([]) will be true).
So you need to simplify the condition logic: maybe using [].some or [].every based on your needs.
const bools = product.reviews.map(
review => review.likes.filter( like => like.user.toString() === req.user.id ).length > 0
)
if (bools.some(b => b === false)){ ...

Breeze-Sequelize with autoGeneratedKeyType Identity

I am trying to create an MS SQL db with breeze-breeze sequelize and i like to generate the ids on the db server. My solution is oriented on the tempHire example from the breeze samples repo
My Metadata.json looks like this:
{
"metadataVersion": "1.0.5",
"namingConvetion": "camelCase",
"localQueryComparisonOptions": "caseInsensitiveSQL",
"dataServices": [{
"serviceName": "breeze/",
"hasServerMetadata": true,
"useJsonp": false
}],
"structuralTypes": [{
"shortName": "User",
"namespace": "Model",
"autoGeneratedKeyType": "Identity",
"defaultResourceName": "Users",
"dataProperties": [{
"nameOnServer": "id",
"dataType": "Int32",
"isPartOfKey": true,
"isNullable": false
}, {
"name": "firstName",
"dataType": "String"
}, {
"name": "lastName",
"dataType": "String"
}, {
"name": "userName",
"dataType": "String",
"isNullable": false,
"maxLength": 64,
"validators": [{
"name": "required"
}, {
"maxLength": 64,
"name": "maxLength"
}]
}, {
"name": "email",
"dataType": "String"
}]
}],
"resourceEntityTypeMap": {
"Users": "User:#Model"
}
}
though this will not create an identity id column.
the created table looks like the following create script:
CREATE TABLE [User] (
[id] INTEGER NOT NULL ,
[firstName] NVARCHAR(255) DEFAULT NULL,
[lastName] NVARCHAR(255) DEFAULT NULL,
[userName] NVARCHAR(64) NOT NULL DEFAULT '',
[email] NVARCHAR(255) DEFAULT NULL,
PRIMARY KEY ([id])
)
In addition here are some breeze server side implementations:
var dbConfig = {
user: 'user',
password: 'secret',
dbName: 'dbname'
};
var sequelizeOptions = {
host: 'hostname',
dialect: 'mssql',
port: 1433
};
function createSequelizeManager() {
var metadata = readMetadata();
var sm = new SequelizeManager(dbConfig, sequelizeOptions);
sm.importMetadata(metadata);
return sm;
}
var _sequelizeManager = createSequelizeManager();
_sequelizeManager.authenticate();
_sequelizeManager.sync(false /* createDb */)
.then(seed)
.then(function () {
console.log('db init successful');
});
Do i have a wrong configuration? Is the Identity not available with the mssql dialect? Am i doing something wrong?
With the configuration is nothing wrong i guess.
I just found out that there is a bug in the MetadataMapper from breeze-sequelize. I tested it with the sequelize version 2.1.3 and 3.x.
The autoIncrement attribute for sequelize will never get set. The if statement will never be true. I'll report this on github. ;)
The fix would be the following code in the MetadataMapper.js at line 134:
if (attributes.type.key == "INTEGER" || attributes.type.key =="BIGINT") {
attributes.autoIncrement = true;
}
In the original code the if statement is attributes.type== "INTEGER" || attributes.type=="BIGINT" where the type actually never is a string.

Waterline.js: Populate association from list

Does anyone know if it's possible to populate a list of IDs for another model using waterline associations? I was trying to get the many-to-many association working but I don't think it applies here since one side of the relationship doesn't know about the other. Meaning, a user can be a part of many groups but groups don't know which users belong to them. For example, I'm currently working with a model with data in mongodb that looks like:
// Group
{
_id: group01,
var: 'somedata',
},
{
_id: group02,
var: 'somedata',
},
{
_id: group03,
var: 'somedata',
}
// User
{
_id: 1234,
name: 'Jim',
groups: ['group01', 'group03']
}
And I'm trying to figure out if it's possible to setup the models with an association in such a way that the following is returned when querying the user:
// Req: /api/users/1234
// Desired result
{
id: 1234,
name: 'Jim',
groups: [
{
_id: group01,
var: 'somedata',
},
{
_id: group03,
var: 'somedata',
}
]
}
Yes, associations are supported in sails 0.10.x onwards. Here is how you can setup the models
Here is how your user model will look like:
// User.js
module.exports = {
tableName: "users",
attributes: {
name: {
type: "string",
required: true
},
groups: {
collection: "group",
via: "id"
}
}
};
Here is how your group model will look like:
// Group.js
module.exports = {
tableName: "groups",
attributes: {
name: {
type: "string",
required: "true"
}
}
};
Setting up models like this will create three tables in your DB:
users,
groups and
group_id__user_group
The last table is created by waterline to save the associations. Now go on and create groups. Once groups are created, go ahead and create user.
Here is a sample POST request for creation a new user
{
"name": "user1",
"groups": ["547d84f691bff6663ad08147", "547d850c91bff6663ad08148"]
}
This will insert data into the group_id__user_group in the following manner
{
"_id" : ObjectId("547d854591bff6663ad0814a"),
"group_id" : ObjectId("547d84f691bff6663ad08147"),
"user_groups" : ObjectId("547d854591bff6663ad08149")
}
/* 1 */
{
"_id" : ObjectId("547d854591bff6663ad0814b"),
"group_id" : ObjectId("547d850c91bff6663ad08148"),
"user_groups" : ObjectId("547d854591bff6663ad08149")
}
The column user_groups is the user id. And group_id is the group id. Now if you fetch the user using GET request, your response will look like this:
{
"groups": [
{
"name": "group1",
"createdAt": "2014-12-02T09:23:02.510Z",
"updatedAt": "2014-12-02T09:23:02.510Z",
"id": "547d84f691bff6663ad08147"
},
{
"name": "group2",
"createdAt": "2014-12-02T09:23:24.851Z",
"updatedAt": "2014-12-02T09:23:24.851Z",
"id": "547d850c91bff6663ad08148"
}
],
"name": "user1",
"createdAt": "2014-12-02T09:24:21.182Z",
"updatedAt": "2014-12-02T09:24:21.188Z",
"id": "547d854591bff6663ad08149"
}
Please note that groups are not embedded in the user collection. Waterline does the fetch from groups, users and group_id__user_group to show this result to you.
Also, if you want to do this in your controller, you will need to execute like this
User.findOne({'id': "547d854591bff6663ad08149"})
.populate('groups')
.exec(function (err, user){
// handle error and results in this callback
});
Without populate('groups'), you won't get the groups array. Hope this serves your purpose

Categories

Resources