is there a way to make synchronous queries to MongoDB?
I'd like to run some code only after I've retrieved all my data from the DB.
Here is a sample snipped.
Code Snippet A
const brandExists = Brands.find({name: trxn.name}).count();
Code Snippet B
if(brandExists == 0){
Brands.insert({
name:trxn.name,
logo:"default.png",
});
Trxs.insert({
userId,
merchant_name,
amt,
});
}
I'd like Code snippet B to run only after Code Snippet A has completed its data retrieval from the DB. How would one go about doing that?
You can use simple async function async function always returns a promise.
const brandExists;
async function brandExist() {
brandExists = Brands.find({
name: trxn.name
}).count();
}
brandExist().then(
// Your Code comes here
if (brandExists == 0) {
Brands.insert({
name: trxn.name,
logo: "default.png",
})
Trxs.insert({
userId,
merchant_name,
amt,
});
});
I don't think using an if statement like the one you have makes sense: the queries are sent after each other; it is possible someone else creates a brand with the same name as the one you are working with between your queries to the database.
MongoDB has something called unique indexes you can use to enforce values being unique. You should be able to use name as a unique index. Then when you insert a new document into the collection, it will fail if there already exists a document with that name.
https://docs.mongodb.com/manual/core/index-unique/
In Meteor, MongoDB queries are synchronous, so it already delivers what you need. No need to make any changes, snippet B code will only run after snippet A code.
When we call a function asynchronous we mean that when that function is called it is non-blocking, which means our program will call the function and keep going, or, not wait for the response we need.
If our function is synchronous, it means that our program will call that function and wait until it's received a response from that function to continue with the rest of the program.
Meteor is based in Node, which is asynchronous by nature, but coding with only asynchronous functions can origin what developers call "callback hell".
On the server side, Meteor decided to go with Fibers, which allows functions to wait for the result, resulting in synchronous-style code.
There's no Fibers in the client side, so every time your client calls a server method, that call will be asynchronous (you'll have to worry about callbacks).
Your code is server-side code, and thanks to Fibers you can be assure that snippet B code will only run after snippet A code.
Related
In the below code, I'm trying to do two operations. One, to create a customer in a db, and the other, to create an event in the db. The creation of the event, is dependent on the creation of the user.
I'm new to Scala, and confused on the role of Futures here. I'm trying to query a db and see if the user is there, and if not, create the user. The below code is supposed to check if the user exists with the customerByPhone() function, and if it doesn't, then go into the createUserAndEvent() function.
What it's actually doing, is skipping the response from customerByPhone and going straight into createUserAndEvent(). I thought that by using a flatmap, the program would automatically wait for the response and that I wouldn't have to use Await.result is that not the case? Is there a way to avoid using Await.result to not block the thread on production code?
override def findOrCreate(phoneNumber: String, creationReason: String): Future[AvroCustomer] = {
//query for customer in db
//TODO this goes into createUserAndEvent before checking that response comes back empty from querying for user
customerByPhone(phoneNumber)
.flatMap(_ => createUserAndEvent(phoneNumber, creationReason, 1.0))
}
You don't need to use Await.result or any other blocking. You do in fact have the result from customerByPhone, you're just ignoring it with the _ . I think what you want is something like this:
customerByPhone(phoneNumber)
.flatMap(customer => {
if(customer == null)
createUserAndEvent(phoneNumber, creationReason, 1.0)
else
Future(customer)
})
You need to code the logic to do something only if the customer isn't there.
I have a piece of code which returns nothing useful:
/**
* Close the web server
*
* #param {function} callback - Called after web server is stopped
*/
PolyApp.prototype.stop = function(callback) {
if (!this._listeningServer) {
if (callback) {
return callback();
}
return;
}
this._listeningServer.close(callback);
};
This function makes use of return to control the execution flow. Given it returns nothing useful I want to avoid documenting it. That gives me the following benefits:
The documentation is more clear as it documents the intention of use
The code is less cluttered with comments that provide no value
I avoid signing a contract of returning something that I do not want to maintain.
On the other hand:
I am returning a value which is not being documented
I think that I should not document it as I do not want people to rely on any returning behavior.
What do you think about? Am I doing right being pragmatic?
What you want to document is up to you. You have to ask yourself the question: "Will I, or other people, ever need to see this documentation to get additional knowledge?". In the case of callbacks that don't need any specific return behavior, you don't need to document anything of it. You should speficy for stop that it'll return whatever the callback returns. People might get confused otherwise.
I'm new to Meteor. I've been stuck on this problem for a while. I can successfully adds items to a collection and look at them fully in the console. However, I cannot access all of the read operations in my .js file.
That is, I can use .find() and .findOne() with empty parameters. But when I try to add .sort or an argument I get an error telling me the object is undefined.
Autopublish is turned on, so I'm not sure what the problem is. These calls are being made directly in the client.
This returns something--
Template.showcards.events({
"click .play-card": function () {
alert(Rounds.find());
}
})
And this returns nothing--
Template.showcards.events({
"click .play-card": function () {
alert(Rounds.find().sort({player1: -1}));
}
})
Sorry for the newbie question. Thanks in advance.
Meteor's collection API works a bit differently from the mongo shell's API, which is understandably confusing for new users. You'll need to do this:
Template.showcards.events({
'click .play-card': function() {
var sortedCards = Rounds.find({}, {sort: {player1: -1}}).fetch();
console.log(sortedCards);
}
});
See this for more details. Also note that logging a cursor (the result of a find) probably isn't what you want. If you want to see the contents of the documents, you need to fetch them.
Rounds.find().sort({player1: -1}) returns a cursor, so you will want to do this:
Rounds.find().sort({player1: -1}).fetch();
Note that this returns an Array of document objects. So you would do something more like this:
docs = Rounds.find().sort({player1: -1}).fetch();
alert(docs[0]);
When I create a query in squeryl, it returns a Query[T] object. The query was not yet executed and will be, when I iterate over the Query object (Query[T] extends Iterable[T]).
Around the execution of a query there has to be either a transaction{} or a inTransaction{} block.
I'm just speaking of SELECT queries and transactions wouldn't be necessary, but the squeryl framework needs them.
I'd like to create a query in the model of my application and pass it directly to the view where a view helper in the template iterates over it and presents the data.
This is only possible when putting the transaction{} block in the controller (the controller includes the call of the template, so the template which does the iteration is also inside). It's not possible to put the transaction{} block in the model, because the model doesn't really execute the query.
But in my understanding the transaction has nothing to do with the controller. It's a decision of the model which database framework to use, how to use it and where to use transactions. So I want the transaction{} block to be in the model.
I know that I can - instead of returning the Query[T] instance - call Iterable[T].toList on this Query[T] object and then return the created list. Then the whole query is executed in the model and everything is fine. But I don't like this approach, because all the data requested from the database has to be cached in this list. I'd prefer a way where this data is directly passed to the view. I like the MySql feature of streaming the result set when it's large.
Is there any possibility? Maybe something like a function Query[T].executeNow() which sends the request to the database, is able to close the transaction, but still uses the MySQL streaming feature and receives the rest of the (selected and therefore fixed) result set when it's accessed? Because the result set is fixed in the moment of the query, closing the transaction shouldn't be a problem.
The general problem that I see here is that you try to combine the following two ideas:
lazy computation of data; here: database results
hiding the need for a post-processing action that must be triggered when the computation is done; here: hiding from your controller or view that the database session must be closed
Since your computation is lazy and since you are not obliged to perform it to the very end (here: to iterate over the whole result set), there is no obvious hook that could trigger the post-processing step.
Your suggestion of invoking Query[T].toList does not exhibit this problem, since the computation is performed to the very end, and requesting the last element of the result set can be used as a trigger for closing the session.
That said, the best I could come up with is the following, which is an adaptation of the code inside org.squeryl.dsl.QueryDsl._using:
class IterableQuery[T](val q: Query[T]) extends Iterable[T] {
private var lifeCycleState: Int = 0
private var session: Session = null
private var prevSession: Option[Session] = None
def start() {
assert(lifeCycleState == 0, "Queries may not be restarted.")
lifeCycleState = 1
/* Create a new session for this query. */
session = SessionFactory.newSession
/* Store and unbind a possibly existing session. */
val prevSession = Session.currentSessionOption
if(prevSession != None) prevSession.get.unbindFromCurrentThread
/* Bind newly created session. */
session.bindToCurrentThread
}
def iterator = {
assert(lifeCycleState == 1, "Query is not active.")
q.toStream.iterator
}
def stop() {
assert(lifeCycleState == 1, "Query is not active.")
lifeCycleState = 2
/* Unbind session and close it. */
session.unbindFromCurrentThread
session.close
/* Re-bind previous session, if it existed. */
if(prevSession != None) prevSession.get.bindToCurrentThread
}
}
Clients can use the query wrapper as follows:
var manualIt = new IterableQuery(booksQuery)
manualIt.start()
manualIt.foreach(println)
manualIt.stop()
// manualIt.foreach(println) /* Fails, as expected */
manualIt = new IterableQuery(booksQuery) /* Queries can be reused */
manualIt.start()
manualIt.foreach(b => println("Book: " + b))
manualIt.stop()
The invocation of manualIt.start() could already be done when the object is created, i.e., inside the constructor of IterableQuery, or before the object is passed to the controller.
However, working with resources (files, database connections, etc.) in such a way is very fragile, because the post-processing is not triggered in case of exceptions. If you look at the implementation of org.squeryl.dsl.QueryDsl._using you will see a couple of try ... finally blocks that are missing from IterableQuery.
I am trying to learn Node.js and using MongoDB.
I got an insert working correctly and can insert as many objects as I want, however I cannot seem to query them at all.
I have tried using every technique posted here and none of them return any of my objects.
I have verified via the Mongo console that the objects exist but I just can't query them and I am absolutely lost as to why.
Here is the current code I'm using to query:
User.findOne({ 'user.name': 'James' }, function(user){
console.log("Got " + user);
res.send(user);
});
Help?
EDIT
The above code returns "null".
Nearly every time I post a question on SO lately I seem to find the answer myself within 15 minutes.
The answer to this one, is that my callback function is only accepting 1 argument of "user". The first argument in the callback is any Errors that are raised, so obviously there are no errors raised.
Changing the callback to this fixes it:
function(err, user) {
}