Meteor Mongo Not Getting Collection Data - javascript

I am trying to get a document from a collection, but it doesn't seem to be working.
when i use the find().fetch(), it returns only an empty array. my code is as follows.
var users = new Mongo.Collection("users");
console.log(users.find());
var userRecord = users.find().fetch();
var returnUserRecord = {};
if (userRecord.length >0){
returnUserRecord = {username:userRecord.username, loginHash:userRecord.loginHash};
console.log("if statement is not complete and the value of the return variable is");
console.log(returnUserRecord);
}
return returnUserRecord
I have checked the database directly and noticed that there is indeed a document in the collection with the command:
meteor mongo
if it makes any difference, all this code in the in the server js file, and is being called from from the client by: Meteor.Methods()/Meteor.call()
EDIT 1
i created another collections with new data from the client, and after selecting the correct database, and running the command:
meteor:PRIMARY> db.newCollection1.find()
i get:
{ "_id" : ObjectId("55d1fa4686ee75349cd73ffb"), "test1" : "asdasd", "test2" : "dsadsa", "test3" : "qweqwe" }
so this confirms that it is available in the database, but running the following in the client console, still doesnt return the result. (autopublish is installed. i tried removing autopublish and made the appropriate changes to subscribe to the table, but that didnt work either).
var coll = new Meteor.Collection('newCollection1');
coll.find().fetch()
this returned an empty array. i have also tried the same on the server.js code using:
meteor debug
but i am still getting an empty array. does anyone know what i might be doing wrong here?
SOLUTION
the solution for this was to create the collection variable in the Meteor object context. this way it can be accessed from the Meteor context.
i.e.
Meteor.coll = new Meteor.Collection('newCollection1');
Meteor.coll.find().fetch();
i hope this helps someone. depending on your code you may want to use a different context.

You don't wait for this subscription to complete, therefore you get empty array.
You should probably read this or this to better understand it.
The thing is you connect users variable to "users" collection, and when you call it, it isn't yet polluted with data (if you don't want to use subscription then maybe use helper - it's reactive so it will return proper value when subscrtiption is finished)

Did you subscribe your users collection somewhere?
if (Meteor.isServer) {
Meteor.publish("users", function(){
return Users.find({})
});
}
if (Meteor.isClient) {
Meteor.subscribe("users");
}

First of all some advice: you can not define a collection twice. If you call new Mongo.Collection("users") a second time you will get an error. Therefore, it should be a global variable an not inside a method.
What I can see in your code is that you are trying to use an array as if it were an object. userRecord.username wont work because userRecord has the value of the fetch() which returns an array.
You could either change your code to userRecord[0].username or loop over the results with forEach like so:
var users = new Mongo.Collection("users");
console.log(users.find());
users.find().forEach(function(singleUser){
console.log(EJSON.stringyfy(singleUser));
}
in order to return the first user, you would be better of using findOne which returns the first object in the result.

Related

Cant read data from collection in MongoDB Atlas Trigger

New to MongoDB, very new to Atlas. I'm trying to set up a trigger such that it reads all the data from a collection named Config. This is my attempt:
exports = function(changeEvent) {
const mongodb = context.services.get("Cluster0");
const db = mongodb.db("TestDB");
var collection = db.collection("Config");
config_docs = collection.find().toArray();
console.log(JSON.stringify(config_docs));
}
the function is part of an automatically created realm application called Triggers_RealmApp, which has Cluster0 as a named linked data source. When I go into Collections in Cluster0, TestDB.Config is one of the collections.
Some notes:
it's not throwing an error, but simply returning {}.
When I change context.services.get("Cluster0"); to something else, it throws an error
When I change "TestDB" to a db that doesnt exist, or "Config" to a collection which doesn't exist, I get the same output; {}
I've tried creating new Realm apps, manually creating services, creating new databases and new collections, etc. I keep bumping into the same issue.
The mongo docs reference promises and awaits, which I haven't seen in any examples (link). I tried experimenting with that a bit and got nowhere. From what I can tell, what I've already done is the typical way of doing it.
Images:
Collection:
Linked Data Source:
I ended up taking it up with MongoDB directly, .find() is asynchronous and I was handling it incorrectly. Here is the reply straight from the horses mouth:
As I understand it, you are not getting your expected results from the query you posted above. I know it can be confusing when you are just starting out with a new technology and can't get something to work!
The issue is that the collection.find() function is an asynchronous function. That means it sends out the request but does not wait for the reply before continuing. Instead, it returns a Promise, which is an object that describes the current status of the operation. Since a Promise really isn't an array, your statment collection.find().toArray() is returning an empty object. You write this empty object to the console.log and end your function, probably before the asynchronous call even returns with your data.
There are a couple of ways to deal with this. The first is to make your function an async function and use the await operator to tell your function to wait for the collection.find() function to return before continuing.
exports = async function(changeEvent) {
const mongodb = context.services.get("Cluster0");
const db = mongodb.db("TestDB");
var collection = db.collection("Config");
config_docs = await collection.find().toArray();
console.log(JSON.stringify(config_docs));
};
Notice the async keyword on the first line, and the await keyword on the second to last line.
The second method is to use the .then function to process the results when they return:
exports = function(changeEvent) {
const mongodb = context.services.get("Cluster0");
const db = mongodb.db("TestDB");
var collection = db.collection("Config");
collection.find().toArray().then(config_docs => {
console.log(JSON.stringify(config_docs));
});
};
The connection has to be a connection to the primary replica set and the user log in credentials are of a admin level user (needs to have a permission of cluster admin)

How to delete a Collection in LokiJS

I been working on LokiJS on Node recently, And I could'nt find a command that deletes the entire Collection itself,
I tried with these commands with an assumption it would exist, I could not find any docs/ samples to delete a collection.
// let result = this.db.dropCollection(collectionName);
// let result = this.db.removeCollection(collectionName);
// let result = this.db.deleteCollection(collectionName);
Other way around I know I can achieve the same by reading the file and removing the entire object, But is there a built-in LokiJS function?
To delete a collection you need to use the removeCollection() method on the main Loki object. See docs here.
For example, if you have your Loki instance initialized like this:
const loki = require('lokijs');
const lokidb = new loki();
// Add a collection (that we will remove later)
let myCollection = lokidb.addCollection('myCollection');
Now lokidb is your main loki object, and this is the object that you need to execute the removeCollection() from.
// Let's remove the collection
lokidb.removeCollection('myCollection');
// * poof * ....
// myCollection is now gone
// To make sure that this deleting change is persisted (if necessary)
lokidb.saveDatabase();
I don't know exactly how you have your loki db set up, but hopefully this example helps.

Data request is sometimes asynchronous

This is a follow-up to a question I posted earlier today. I'm going through this book on using AngularJS with Firebase, which lead me to post this question. I found a solution, but what I still don't understand is that the example in the API Documentation for a $firebaseArray doesn't seem to be handling it as an asynchronous request.
var list = $firebaseArray(new Firebase(URL));
// add an item
list.$add({ foo: "bar" }).then(...);
// remove an item
list.$remove(2).then(...);
// make the list available in the DOM
$scope.list = list;
Also, the example from the books seems to treat the request synchronously as well.
# Service
var buildingsUri = FIREBASE_URI + '/buildings';
var ref = new Firebase(buildingsUri);
var buildings = $firebaseArray(ref);
var getBuildings = function () {
return buildings;
};
...
# Controller
$scope.buildings = syncArraySvc.getBuildings();
How is it that $scope.list in the first example and $scope.buildings in the second example could be properly populated with data when they haven't checked to make sure the request has completed?
The $add and $remove methods return promises. The $firebaseArray() method returns an array with some special functions and properties added. Neither $add or $remove require the data to be loaded locally or depend on the state of the data, so they can be called synchronously. The data is still downloaded asynchronously, of course. So, for example:
var list = $firebaseArray(new Firebase(URL));
// add an item
list.$add({ foo: "bar" }).then(function(ref) {
console.log('added', ref.key());
});
// remove an item
list.$remove(2).then(function(ref) {
console.log('removed', ref.key());
});
console.log('list current contains', list.length, 'items');
list.$loaded(function() {
console.log('after loading initial data, the list contains', list.length, 'items');
});
Assuming the list contains 10 items at load time, and that list is not changed remotely during this code execution, we would see output similar to the following:
list currently contains 0 items
after loading initial state, the list contains 10 items
added abc123
removed xyz456
Additionally, I'd note that this code is probably superfluous. Usually when we see code like this, it's because devs are trying to turn Firebase into a CRUD model. You can probably just return $firebaseArray() there instead and use the existing methods like $getRecord(), et al, instead of artificially wrapping the API in your service.

How do I update the values of this variable between modules?

So I have module "bot.js" and in this module, it constantly checks for messages and assigns them to a variable (db_users). Since I run my app from "app.js", and I pass the functions that continuously populates db_users, how do I get this information to "app.js"?
Bot.js is using an IRC function that stores user's messages.
var db_users = []
// I then populate db_users with the previous data that is already in mongodb
// using a .find().exec() mongodb command.
bot.addListener('message', function (from, to, text) {
userInfo.checkForUser(db_users);
// checkForUser basically looks through the variable db_users to see if
// there is a username that matches the "from" parameter in the listener
// If it's not there, push some user information into the db_users array
// and create a new MongoDB record.
}
So I have all this, but my main app is a website that can control this "bot" (It's not a spam bot, but a moderation/statistical bot), and I'm using a require function to use "./bot.js" in "app.js"
app.js
bot = require('./bot');
So how would I constantly use the data in bot.js, in app.js? I'm a little fuzzy on how modules work.
Yeah I could just put all of the contents of app.js in bot.js, but it would be too annoying to look through.
Thanks!
Put db_users inside an object so that it's just a reference. Make changes to that reference instead. Then export that outer object. Now since db_users is just a reference, it'll always be a latest copy of whatever it refers to.
bot.js
var data = module.exports = {};
data.db_users = [];
bot.addListener('message', function (from, to, text) {
userInfo.checkForUser(data.db_users);
}
app.js
botData = require('./bot');
botData.db_users will always have the whatever latest changes were made to data.db_users in bot.js

Deps autorun in Meteor JS

Decided to test out Meteor JS today to see if I would be interested in building my next project with it and decided to start out with the Deps library.
To get something up extremely quick to test this feature out, I am using the 500px API to simulate changes. After reading through the docs quickly, I thought I would have a working example of it on my local box.
The function seems to only autorun once which is not how it is suppose to be working based on my initial understanding of this feature in Meteor.
Any advice would be greatly appreciated. Thanks in advance.
if (Meteor.isClient) {
var Api500px = {
dep: new Deps.Dependency,
get: function () {
this.dep.depend();
return Session.get('photos');
},
set: function (res) {
Session.set('photos', res.data.photos);
this.dep.changed();
}
};
Deps.autorun(function () {
Api500px.get();
Meteor.call('fetchPhotos', function (err, res) {
if (!err) Api500px.set(res);
else console.log(err);
});
});
Template.photos.photos = function () {
return Api500px.get();
};
}
if (Meteor.isServer) {
Meteor.methods({
fetchPhotos: function () {
var url = 'https://api.500px.com/v1/photos';
return HTTP.call('GET', url, {
params: {
consumer_key: 'my_consumer_key_here',
feature: 'fresh_today',
image_size: 2,
rpp: 24
}
});
}
});
}
Welcome to Meteor! A couple of things to point out before the actual answer...
Session variables have reactivity built in, so you don't need to use the Deps package to add Deps.Dependency properties when you're using them. This isn't to suggest you shouldn't roll your own reactive objects like this, but if you do so then its get and set functions should return and update a normal javascript property of the object (like value, for example), rather than a Session variable, with the reactivity being provided by the depend and changed methods of the dep property. The alternative would be to just use the Session variables directly and not bother with the Api500px object at all.
It's not clear to me what you're trying to achieve reactively here - apologies if it should be. Are you intending to repeatedly run fetchPhotos in an infinite loop, such that every time a result is returned the function gets called again? If so, it's really not the best way to do things - it would be much better to subscribe to a server publication (using Meteor.subscribe and Meteor.publish), get this publication function to run the API call with whatever the required regularity, and then publish the results to the client. That would dramatically reduce client-server communication with the same net result.
Having said all that, why would it only be running once? The two possible explanations that spring to mind would be that an error is being returned (and thus Api500px.set is never called), or the fact that a Session.set call doesn't actually fire a dependency changed event if the new value is the same as the existing value. However, in the latter case I would still expect your function to run repeatedly as you have your own depend and changed structure surrounding the Session variable, which does not implement that self-limiting logic, so having Api500px.get in the autorun should mean that it reruns when Api500px.set returns even if the Session.set inside it isn't actually doing anything. If it's not the former diagnosis then I'd just log everything in sight and the answer should present itself.

Categories

Resources