How to do dynamic queries on MySQL from Meteor? - javascript

I have been trying to make dynamic queries against MySQL from Meteor using the numtel:mysql package. So far it's not successful. Perhaps I either need to know how to pass a dynamic argument to the subscribe, or need to know how to get the result of liveDb.select as an array or object rather than a cursor (liveDb is instantiated by called new LiveMysql(...)). I have tried doing the query in a method on the server side (as declared in Meteor.methods(...), and the method does not return the result. If anyone has code examples for this, that would be very much appreciated!

Here is helpful links for use Meteor with MySQL for select query, execute stored procedure,user mongo like publish subscribe method as well as join query in publish.
MySql:numtel package
Leaderboard MySql example
// The below code reference from Leaderboard MySql example
Meteor.publish('allPlayers', function() {
return liveDb.select(
'SELECT * FROM players ORDER BY score DESC',
[ { table: 'players' } ]
);
});
Meteor.publish('playerScore', function(name) {
return liveDb.select(
'SELECT id, score FROM players WHERE name = ' + liveDb.db.escape(name),
[
{
table: 'players',
condition: function(row, newRow, rowDeleted) {
// newRow provided on UPDATE query events
return row.name === name || (newRow && newRow.name === name);
}
}
]
);
Meteor.methods({
'incScore': function(id, amount) {
check(id, Number);
check(amount, Number);
liveDb.db.query(
'UPDATE players SET score = score + ? WHERE id = ?', [ amount, id ]);
}
});

You need to call change on your MysqlSubscription with the same params as defined in the Meteor.publish.
In my case:
export const mySqlSubscription = new MysqlSubscription('tableName');
Meteor.publish('tableName', function(filters){
var filterString = buildFilterString(filters);
var qString = 'SELECT ..... FROM tableName '+filterString;
//console.log(qString);
return liveDb.select( qString, [ { table: 'tableName' } ] );
}
);
Then whenever I want to update my subscription for a different filter I call:
mySqlSubscription.change(this.getReactively('filterRecord'));

Related

How to order contacts by last message date with Sequelize?

I'm trying to create a chat app in nodejs with Sequelize for my db.
Everything works great but when i try to show all user friends ordered by the last message date i have a bug.
To get the users with there messages it works with associations but ordering doesn't.
Here is my function to get messages:
const getFriends = (id, limit) => {
return new Promise(async (resolve, reject) => {
try {
const user = await Follows.findAll({
where: {
[Op.or]: {
follower_id: id,
followed_id: id
},
},
include: Messages
order: [[Messages, 'createdAt', 'DESC']],
limit
})
resolve(user)
} catch (e) {
reject(e)
}
})
}
So Seqeulize does the query but not in the way that I want to.
Here is the query generated by Sequelize:
SELECT `follows`.*,
`messages`.*
FROM (
SELECT `follows`.* FROM `follows`
WHERE (
`follows`.`follower_id` = 3
OR
`follows`.`followed_id` = 3
)
AND `follows`.`reciprocal` = true
LIMIT 1
)
LEFT OUTER JOIN `messages` ON `follows`.`id` = `messages`.`pairId`
ORDER BY `messages`.`createdAt` DESC;
As you see here the ORDER BY messages.createdAt DESC; happens at the end, but after the FROM you can see he does a query to the table i'm already querying.
Which is not LOGIC !!
I would like to my sql query to look like that:
SELECT `follows`.*,
`messages`.*
FROM `follows`
LEFT OUTER JOIN `messages` ON `follows`.`id` = `messages`.`pairId`
WHERE (
`follows`.`follower_id` = 3
OR
`follows`.`followed_id` = 3
)
AND `follows`.`reciprocal` = true
ORDER BY `messages`.`createdAt` DESC
LIMIT 1
That means that I want my where and my limit to be in the parent query and not in the FROM query.
I really don't know how to do this with Sequelize and didn't find someone having same issue on the internet.
I would be really happy to have some help!
Actualy I found the answer.
I just needed to add subQuery:false and it worked as I wanted !

How to create a `context.Provider`/`context.Consumer`-like structure to pass values in a bot app?

I'm trying to pass a property, that is inside the first position of an array of objects, to another module so I can use this value later. I've tried to pass it as module(args), but it keeps reading the default value which is 0. Is there a way to do this?
I tried to implement some React.context but the Bot framework Emulator is refusing it.
/////////////////Module that ll acquire the value/////////////////////////////
getCard(bot, builder, params) {
let configValues = { ...params[0] }
bot.dialog(`${configValues.path}`, function (session) {
var msg = new builder.Message(session);
const cardItem = (obj) => {
return (new builder.HeroCard(session)
.title(`${obj.title}`)
.text(`R$ ${obj.price}`)
.images([builder.CardImage.create(session, `${obj.img}`)])
.buttons([
builder.CardAction.imBack(session, `${obj.price} Item adicionado!`, 'add to cart')
// !onClick event must add the current obj.price to
// the configValues.total(Ex: configValues.total += obj.price)!
])
)
}
msg.attachmentLayout(builder.AttachmentLayout.carousel)
msg.attachments(
eval(params.map(obj => cardItem(obj)))
);
//!in here before end the dialog is where i want to update
// the configValues.total so i can show it in the -> Checkout module
session.send(msg).endDialog()
}).triggerAction({ matches: configValues.regex });
}
}
//////////////CheckOut.Module///////////////////////////////
{...}
let configValues = { ...params[0] }
let state = {
nome: "",
endereco: "",
pagamento: "",
total: configValues.total // this is the value to be read
}
bot.dialog('/intent', [
{...},
(session, results) => {
state.pagamento = results.response
session.send(
JSON.stringify(state) // here is the place to be printed
)
{...}
]
).triggerAction({ matches: /^(finalizar|checar|encerrar|confirmar pedido|terminar)/i })
Since you solved your original problem, I'll answer the one in your comment.
Your problem is here:
cartId.map((obj, i , arr) => {
// if (!obj.total) {
// obj.total.reduce(i => i += i)
// }
const newtotal = new total
newtotal.getTotals(bot, builder, obj, arr)
})
cartId contains the totals for each of your items. When you call map on it, you're passing each item individually to getTotals, which passes each item to checkout()
The reason you can't sum all of the totals and can only sum one item's total is that you pass cartId to checkout and cartId has been changed to just a single item. Instead, there's a couple of different things you could do:
Pass the whole cartId from cartItems and use something like for (var key in cartItems) in totalConstructor() and checkoutConstructor(). This is probably the easiest, but not very memory efficient.
Use BotBuilder's State Storage to store your totals array in userData, then sum that at the end. This might be more difficult to implement, but would be a much better route to go. Here's a sample that can help you get started.

deepstream list subscribing to data

is it possible in deepstream to subscribe to data using a list? it appears that changes to the data does not trip the subscribe() function, only something like an addEntry() appears to affect the list subscription.
const deepstream = require('deepstream.io-client-js') ;
const util = require('util') ;
const client = deepstream('localhost:6020').login();
var obj_1 = { 'sequelizeName':'Mark', 'sequelizeAddr':'123 Elm Lane' , 'sequelizeId':'1111'};
var obj_2 = { 'sequelizeName':'Lori', 'sequelizeAddr':'948 Maple Street' , 'sequelizeId':'2222'};
const rec_1 = client.record.getRecord('obj_one');
const rec_2 = client.record.getRecord('obj_two');
rec_1.set(obj_1);
rec_2.set(obj_2);
var listTest = client.record.getList('listTest');
listTest.setEntries( ['obj_one' ,'obj_two' ] );
listTest.subscribe( (result) => {
console.log('LIST SUBSCRIBE: ' + util.inspect(result));
})
setTimeout( () => {
obj_1.sequelizeAddr = '321 New Address';
rec_1.set(obj_1); // how can this change show up in the list subscribe?
}, 2000 );
I have been encouraged to try a new approach using lists, but I am unclear how to subscribe to changes in the data itself using a list, except to somehow have some sort of "generic" or "global" subscribe, which i am not sure is even possible.
Or is there some way I can subscribe using an anonymous record?
Lists are just arrays of strings. Your list content is not connected to the actual record. You can't even assume that a list entry is a record name. You would need to subscribe to each record name in a list manually to get its content updates.
this suggestion was made by both wolfram and phillipp:
class User{
constructor( recordName ) {
this.record = ds.record.getRecord( recordName );
this.record.subscribe( this._processUpdate.bind( this ) );
}
_processUpdate( data ) {
if( this.record.name === '...') {
// do stuff
}
}
}
this works great. thank you both.

FireBase - angularfire setting object key as variable

I am using firebase(angularfire) in my angularjs app to store and process my message system but can't seem to figure out how to replicate the example data from the firebase docs
// room members are easily accessible (or restricted)
// we also store these by room ID
"members": {
// we'll talk about indices like this below
"one": {
"mchen": true,
"hmadi": true
}
}
Here the members.one contains the user name as a key and I am trying to do this for my data as well but can't seem to figure out a solution.
The members portion of my firebase data is like so:
members { one: { } }
I have two variables set in the $scope.
user_name = kep; //person chatting with name
sender_name = pek; //current user name
So I want to use the set function to insert data into members.one or in this case members.user_name + ':' + sender_name but where I am having trouble is how to actually insert the data without creating a parent object.
ref.child('members').child(user_name + ':' + sender_name).set({
user_name: true, sender_name: true
});
The problem arises when I try to pass user_name and sender_name into the set() function below is the result it gets.
members { "kep:pek": { user_name: true, sender_name: true }}
where as I want it to be:
members { "kep:pek": { kep: true, pek: true }}
If I put user_name and sender_name into an object and then run the set() function with the object passed it will create the following structure which is not what I am looking for:
members { "kep:pek": { newObject: { kep: true, pek: true }}}
Firebase team member here.
The Firebase Database is a just a JSON document.
So let's say you want to structure your data this way:
{
"members" : {
"kep:pek" : {
"kep" : true,
"pek" : true
}
}
}
A custom key is created by using the .child() method, or by creating a key in the JavaScript Object.
JSBin Demo
var rootRef = new Firebase('<my-firebase-app>');
var membersRef = rootRef.child('members');
var user_name = 'kep';
var sender_name = 'pek';
// child object to store custom keys
var objectToSave = {};
// set keys in [] syntax
objectToSave[user_name] = true;
objectToSave[sender_name] = true;
// use .child() with a formatted string to save the object
membersRef.child(user_name + ':' + sender_name).set(objectToSave);

How to design a chained Model.find() function?

I'm trying to write a ORM in Node.js. I want to declare a class named Model which will be used to declare a data object, like:
Users = new Model(someModelRules);
newUser = new Users(userInfomation);
the data model User have a function named find(). Now, I want to make find() chained, like:
Users.find(" name = 'John' ")
.orderedBy("age").desc()
.limit(0,10)
or maybe just a simply find:
Users.find(" name = 'John' ")
to code this find function, I believe I must build the SQL first,and do the SQL query at the end of this find chain.
I don't know how to do this, all I can think of is to add a function like: doQuery(), so I will know it's time to do the SQL query when the doQuery() function was called, like:
Users.find(" name = 'John' ")
.orderedBy("age").desc()
.limit(0,10)
.doQuery();
I know this is a simply solution, but I don't want the extra doQuery() function. :(
So, how should I design this? It would so nice of you if you can show me some example code with comments.
Thx! (sorry for my poor English)
ps. I know the ORM2 has a find function I just want, but I wanna know how to code it and I can barely understand the code in ORM2 as there are no comments. (I'm not gonna use orm2.)
================================= SOLUTION ==============================
Inspired by #bfavaretto :
function User() {
this.find = function(id, condition) {
return new findChain(id, condition);
}
}
function findChain(id, condition) {
this._id = id
this._condition = condition
this.queryTimerSet = false;
this.scheduleQuery = function () {
var self = this;
if(!self.queryTimerSet) {
console.log('[TEST CASE: ' + self._id + '] Insert query into eventLoop');
setTimeout(function(){
console.log('[TEST CASE: ' + self._id + '] Start query: '+self._condition);
}, 0);
self.queryTimerSet = true;
} else {
console.log('[TEST CASE: ' + self._id + '] No need to insert another query');
}
}
this.orderedBy = function(column) {
console.log('[TEST CASE: ' + this._id + '] orderedBy was called');
this._condition = this._condition + ' ORDER BY ' + column
this.scheduleQuery();
return this;
}
this.desc = function() {
// simply add DESC to the end of sql
this._condition = this._condition + ' DESC'
}
this.scheduleQuery();
}
var user = new User();
user.find(1,'SELECT * FROM test').orderedBy('NAME1').desc();
user.find(2,'SELECT * FROM test').orderedBy('NAME2');
user.find(3,'SELECT * FROM test');
runnning this code, you will get the result:
[TEST CASE: 1] Insert query into eventLoop
[TEST CASE: 1] orderedBy was called
[TEST CASE: 1] No need to insert another query
[TEST CASE: 2] Insert query into eventLoop
[TEST CASE: 2] orderedBy was called
[TEST CASE: 2] No need to insert another query
[TEST CASE: 3] Insert query into eventLoop
[TEST CASE: 1] Start query: SELECT * FROM test ORDER BY NAME1 DESC
[TEST CASE: 2] Start query: SELECT * FROM test ORDER BY NAME2
[TEST CASE: 3] Start query: SELECT * FROM test
I believe there must be a better way to achieve this, but this is the best I can get for now.
Any comments?
It is possible to achieve that if you schedule the doQuery logic to run asynchronously (but as soon as possible). I am thinking on something like this:
function User() {
// Flag to control whether a timer was already setup
var queryTimerSet = false;
// This will schedule the query execution to the next tick of the
// event loop, if it wasn't already scheduled.
// This function is available to your model methods via closure.
function scheduleQuery() {
if(!queryTimerSet) {
setTimeout(function(){
// execute sql
// from the query callback, set queryTimerSet back to false
}, 0);
queryTimerSet = true;
}
}
this.find = function() {
// ... logic that builds the sql
scheduleQuery();
return this;
}
this.orderedBy = function() {
// ... logic that appends to the sql
scheduleQuery();
return this;
}
// etc.
}
One totally different approach is to have a single method for building the SQL, and passing the ORDER BY and LIMIT parameters in an options object. Then your call would look like this:
user.find({
what : " name = 'John' ",
orderedBy : "age DESC",
limit : "0,10"
});
This is more suited for SQL queries than what you're trying to do. What you have looks like noSQL stuff like MongoDB, where fetching the records and sorting are separate operations (I think).
You will always have to have a execute/doQuery function at the end of the chain.
This is because all the other functions before the doQuery help build the query that needs to be executed at the end.

Categories

Resources