I am working with Azure Mobile app and here is my SQL statement
return new Promise((resolve, reject) => {
var query = {
sql: "SELECT Id FROM Groups WHERE Members LIKE '%#userId%' and Members '%#friendId%' and type = #roomType ",
parameters: [
{ name: 'userId', value: userId},
{ name: 'friendId', value: friendId },
{ name: 'roomType', value: type }
]
};
context.data.execute(query)
.then(function (results) {
resolve(results);
}).catch(error => { reject (error);});
});
and I go to SQL and fill all variable like this
SELECT Id FROM Groups Where Members LIKE '%05adf56b-c128-4203-802f-d8d0e2916210%' and Members LIKE '%21B69402-7E9C-4BA3-99A8-6D84A96FA866%' and type = 0
and i got many records. so i didn't know what i did wrong
It seems that your SQL statement looks incorrect, you may miss a like keyword for Members '%#friendId%'.
I have tested the following SQL statement on my azure mobile app, it returns nothing.
SELECT Id FROM Groups WHERE Members LIKE '%#userId%'
After some trials, I found the following statement could work as expected:
var query = {
sql: "SELECT * FROM test5 where name LIKE #name",
parameters: [
{name:"name",value:"%"+req.query.param1+"%"}
]
};
SELECT Id FROM Groups Where Members LIKE '%05adf56b-c128-4203-802f-d8d0e2916210%' and Members LIKE '%21B69402-7E9C-4BA3-99A8-6D84A96FA866%' and type = 0
and i got many records. so i didn't know what i did wrong
Based on your description, it seems that your Members column contains many GUIDs. You need to check your table records by yourself, or you could update your question with more details about your records for us to narrow down this issue.
Related
i want to send every user who logs in a list of unique records i.e not same records from the database,
for every user i want to skip the records that have already been sent to other signed users.bare with me ,am a beginner,how can i implement such?
here is the code that fetches the records from the database
phrases.findAll({
where: {
userId: user.id,
phraseStatus: 1
},
limit: 10,
offset,
10
})
.then((data) => {
userObj.phrases.push(...data);
return res.status(200).json(userObj);
});
You will need to keep track of what has been sent to other users. I suggest you keep a table like phrases_sent to record what has been sent so far. Add the phrase_id to this new table so you have a relationship.
Take a look at associations in the docs.
You can then query the phrases table by outer joining to your phrases_sent table to return phrases that have not been sent so far.
Something like:
const phrases = await sequelize.models.phrase.findAll({
where: {
'$phrasesSents.phrase_id$': {[Op.is]: null} // query the joined table
},
attributes: ['phrase.phrase'], // the unused phrases
include: [
{
attributes: [],
model: sequelize.models.phrasesSent,
required: false, // specify this is a left outer join
}
],
raw: true,
nest: true
});
Would yield:
SELECT "phrase"."phrase"
FROM "phrases" AS "phrase"
LEFT OUTER JOIN "phrases_sent" AS "phrasesSents" ON "phrase"."id" = "phrasesSents"."phrase_id"
WHERE "phrasesSents"."phrase_id" IS NULL;
I believe doing a LEFT OUTER JOIN has performance benefits over a NOT IN (SELECT ...) style query.
I have a JSONB column in DB.
I'd like to have request to DB where I can check if some value in this JSON it true or false:
SELECT *
FROM table
WHERE ("json_column"->'data'->>'data2')::boolean = true AND id = '00000000-1111-2222-3333-456789abcdef'
LIMIT 1
So, my sequelize request:
const someVariableWithColumnName = 'data2';
Model.findOne({
where: {
[`$("json_column"->'data'->>'${someVariableWithColumnName}')::boolean$`]: true,
id: someIdVariable,
},
order: [/* some order, doesn't matter */],
})
And sequelize generate bad result like:
SELECT *
FROM table
WHERE "(json_column"."->'data'->>'data2')::boolean" = true AND id = '00000000-1111-2222-3333-456789abcdef'
LIMIT 1
Split my column by . and add " to every element.
Any idea how to get rid of adding " to the column in where condition?
Edit:
Here is my query with sequelize.literal():
const someVariableWithColumnName = 'data2';
Model.findOne({
where: {
[sequelize.literal(`$("json_column"->'data'->>'${someVariableWithColumnName}')::boolean$`)]: true,
id: someIdVariable,
},
order: [/* some order, doesn't matter */],
})
You can use Sequelize.literal() to avoid spurious quotes. IMHO, wrapping the json handling in a db function might also be helpful.
I just came across a similar use case.
I believe you can use the static sequelize.where method in combination with sequelize.literal.
Here is the corresponding documentation in sequelize API reference: https://sequelize.org/master/class/lib/sequelize.js~Sequelize.html#static-method-where
And here is an example (although I will admit hard to find) in the regular documentation:
https://sequelize.org/master/manual/model-querying-basics.html#advanced-queries-with-functions--not-just-columns-
In the end for your specific sit try something like this:
const someVariableWithColumnName = 'data2';
Model.findOne({
where: {
[Op.and]: [
// We provide the virtual column sql as the first argument of sequelize.where with sequelize.literal.
// We provide the matching condition as the second argument of sequelize.where, with the usual sequelize syntax.
sequelize.where(sequelize.literal(`$("json_column"->'data'->>'${someVariableWithColumnName}')::boolean$`), { [Op.eq]: true }),
{ id: someIdVariable }
]
})
Suppose we have a such structure in NodeJs Sequelize.
var User = sequelize.define('user', {/* ... */})
var Project = sequelize.define('project', {/* ... */})
Project.hasMany(User)
In this part of video presenter offers to save embedded objects with two steps using promises. In our case it would be something like:
Project.create({
...
}).then(function(project){
User.create({
...
projectId:project.id
})
})
But this approach will result two db calls.
So, is it possible to save embedded objects (Project which contains User e.g. User must have Project's id as a foreign key) into the db with one db call or within a transaction using Sequelize?
You should be able to insert parent-children by passing an array of objects into a key with the same name as the "as" value used on the "include". Although the documentation is light on the usage, you can see it handled in the source code here.
No promises (pun semi-intended) that this is actually run in single SQL query, not sure of the exact implementation in Sequelize. You should be able to enable logging (logging: console.log in the Sequelize(options)) to see what it's running.
// specify an "as" value and require a User.project_id value
Project.hasMany(User, { as: 'Users', foreignKey: { allowNull: false } });
// define your Project -> Users as json with the "as" value as the key
const project = {
name: 'project name',
Users: [
{
name: 'user 1',
},
{
name: 'user 2',
},
],
};
// create a transaction and "include" the Model in the create, txn falls back in .catch()
sequelize.transaction(t =>
Project.create(project, {
include: [{
model: User,
as: 'Users',
}],
transaction: t,
})
)
.catch(e => console.log('the txn failed because', e));
A few questions about storing user data in MongoDB. What is the best place in mongo to store user specific data, such as User settings, User photo url, User friends, User events?
In Mongo, user data is stored in:
Meteor
/ Collections
/ users
/ _id
/ profile
/ services
Should I add there a new collections? In a following way:
/ events / _id's
/ friends / _id's
/ messages / _id's
/ settings
How should I publish user's private data and manipulate this collections, to be sure it's save and no one else will modify or have access to private data of another person.
You can add data to the users profile field like this:
Meteor.users.update( id, { $set: { 'profile.friends': someValue } } );
To only publish specific fields you can do something like this:
Meteor.publish( 'users', function () {
return Meteor.users.find( {}, { fields: { 'profile.friends': 1 } } );
});
Hope this helps.
Normalization
"Database normalization is the process of organizing the attributes and tables of a relational database to minimize data redundancy."
MongoDB is a non relational database. This makes normalized data hard to query for. This is why in MongoDB we denormalize data. That makes querying for it easier.
It depends on your use-case. The question is basically when to demormalize. It's mostly a matter of opinion. But objective here are some pros and cons:
Pros to demormalization
It's easier to retrieve data (Due to Mongo not beeing a relational DB)
It performs better if you are always getting the data in bulk
Cons to demormalization
It doesn't scale well for things like user.messages (You can't just publicize some messages)
In your case I'd definitly go for seperate collections for events, friends and messages. Setting can't expand infinitly. So I'd put it into the users collection.
Security
I'd use a publications and allow and deny for this. Let me make an example for Messages:
Collection
Messages = new Mongo.Collection('Messages')
Messages.insert({
sender: Meteor.userId,
recipient: Meteor.users.findOne()._id,
message: 'Hello world!'
})
Publication
Meteor.publish('userMessages', function (limit) {
return Messages.subscribe({
$or: [
{sender: this.userId},
{recipient: this.userId}
]
}, {limit: limit})
})
Allow
function ownsMessage (user, msg) {
return msg.sender === user ? true : false
}
Messages.allow({
insert: function (userId, newDoc) {
!!userId
},
update: function (userId, oldDoc, newDoc) {
if(
ownsMessage(userId, oldDoc) &&
ownsMessage(userId, newDoc)
) return true
return false
},
remove: function () {
return false
}
})
This code is untested, so it might contain small errors
I'm building a simple database with node, express and sequelize. I have created my models, and sequelize created the tables in my database.
I have the models User and City, with a many to many relationship. Sequelize created the tables Users, Cities and a join table CitiesUsers: with UserId and CityId.
My question is when I create a new user how do I update that join table? The CityId property gets ignored on create.
//Models use
//City.hasMany(User);
//User.hasMany(City);
var user = User.build({
first_name: 'John',
last_name: 'Doe',
CityId: 5
});
user.save();
After digging further into the documentation, I believe I've found the answer.
When creating a many to many relationship sequelize creates get, set and add methods to each model.
From the docs assuming models User and Project with many to many:
http://docs.sequelizejs.com/en/latest/docs/associations/#belongs-to-many-associations
This will add methods getUsers, setUsers, addUsers to Project, and
getProjects, setProjects and addProject to User.
So in my case I did the following where "city" is a specific City model returned from City.find...
//user.setCities([city]);
models.User.find({ where: {first_name: 'john'} }).on('success', function(user) {
models.City.find({where: {id: 10}}).on('success', function(city){
user.setCities([city]);
});
});
You can create a new instance of the model used as the join table once both City and User models have been created.
const User = sequelize.define('user')
const City = sequelize.define('city')
const UserCity = sequelize.define('user_city')
User.belongsToMany(City, { through: UserCity })
City.belongsToMany(User, { through: UserCity })
const user = await User.create()
const city = await City.create()
const userCity = await UserCity.create({
userId: user.userId,
cityId: city.cityId,
})
Just to add on to the many excellent answers in this thread, I find generally that when I have one entity referencing another, I want to create the referenced entity if (and only if) it does not already exist. For this I like to use findOrCreate().
So imagine you were storing articles, and each article could have any number of tags. What you'd typically want to do is:
Iterate through all the desired tags, and check if they exist. Create them if they don't already exist.
Once all the tags have been found or created, create your article.
Once your article has been created, link it to the tags you looked up (or created) in step 1.
For me, this winds up looking like:
const { article, tags } = model.import("./model/article");
let tagging = [
tags.findOrCreate({where: {title: "big"}}),
tags.findOrCreate({where: {title: "small"}}),
tags.findOrCreate({where: {title: "medium"}}),
tags.findOrCreate({where: {title: "xsmall"}})
];
Promise.all(tagging).then((articleTags)=> {
article.create({
title: "Foo",
body: "Bar"
}).then((articleInstance) => {
articleInstance.setTags(articleTags.map((articleTag) => articleTag[0]));
})
})
From The docs v3:
// Either by adding a property with the name of the join table model to the object, before creating the association
project.UserProjects = {
status: 'active'
}
u.addProject(project)
// Or by providing a second argument when adding the association, containing the data that should go in the join table
u.addProject(project, { status: 'active' })
// When associating multiple objects, you can combine the two options above. In this case the second argument
// will be treated as a defaults object, that will be used if no data is provided
project1.UserProjects = {
status: 'inactive'
}
u.setProjects([project1, project2], { status: 'active' })
// The code above will record inactive for project one, and active for project two in the join table