How do you access a collection from the meteor shell? - meteor

I'm trying to execute this query in a meteor shell, I need to use the meteor shell because one of the query parameters is a moment object.
date = moment().subtract(5, 'hours').toDate()
return Messages.find {createdAt: {$gte: date}}
In meteor shell:
> Messages = new Mongo.Collection("messages")
Error: A method named '/messages/insert' is already defined
> Messages
ReferenceError: Messages is not defined
I have to run the code in the meteor shell because the query uses moment objects.

I was able to do this by calling the following on the Meteor Shell:
MyCollection = Mongo.Collection.get("collectionName");
Replace "collectionName" with a string containing the name of the mongo db collection.
Also Mongo.Collection.getAll() to return all collections on the shell.

Related

How to call a Meteor method from the command line

I have a Meteor app and want to call a server method from the command line, so that I can write a bash script to perform scheduled operations.
Is there any way to either call a method directly, or submit a form which will then trigger server-side code?
I've tried using curl to call a method, but either it's not possible or I'm missing something basic. This doesn't work:
curl "http://localhost:3000/Meteor.call('myMethod')"
nor does:
curl -s -d "http://localhost:3000/imports/api/test.js" > out.html
where test.js:
var test = function(){
console.log('hello');
}
I thought of using a form but I can't think how to create a submit event because the Meteor client uses template events that then call server methods.
I'll be very grateful for any help! This feels like it should be a simple thing but has me stumped.
Edit: I've also tried phantomjs and slimerjs as run through casperjs.
phantomjs is no longer maintained and generates an error:
TypeError: Attempting to change the setter of an unconfigurable property.
https://github.com/casperjs/casperjs/issues/1935
slimerjs errors with Firefox 60 and I can't figure out how to 'downgrade' back to the supported 59, and the option to disable automatic updates of Firefox no longer seems to exist. The error is:
c is undefined
https://github.com/laurentj/slimerjs/issues/694
You could make use of the node ddp package to call the Meteor method in an own js file that you created with a specific script. From there you can pipe all outs to wherever you want.
Let's assume the following Meteor method:
Meteor.methods({
'myMethod'() {
console.log("hello console")
return "hello result"
}
})
The upcoming steps will let you call this method from another shell, assuming your Meteor application is running.
1. Install ddp in your global npm directory
$ meteor npm install -g ddp
2. Create the script to call your method in your test directory
$ mkdir -p ddptest
$ cd ddptest
$ touch ddptest.js
Place the ddp script code into the file with the editor or command of your choice.
(The follwing code is freely taken from the package's readme. Feel free to configure to your needs.)
ddptest/ddptest.js
var DDPClient = require(process.env.DDP_PATH);
var ddpclient = new DDPClient({
// All properties optional, defaults shown
host : "localhost",
port : 3000,
ssl : false,
autoReconnect : true,
autoReconnectTimer : 500,
maintainCollections : true,
ddpVersion : '1', // ['1', 'pre2', 'pre1'] available
// uses the SockJs protocol to create the connection
// this still uses websockets, but allows to get the benefits
// from projects like meteorhacks:cluster
// (for load balancing and service discovery)
// do not use `path` option when you are using useSockJs
useSockJs: true,
// Use a full url instead of a set of `host`, `port` and `ssl`
// do not set `useSockJs` option if `url` is used
url: 'wss://example.com/websocket'
});
ddpclient.connect(function(error, wasReconnect) {
// If autoReconnect is true, this callback will be invoked each time
// a server connection is re-established
if (error) {
console.log('DDP connection error!');
console.error(error)
return;
}
if (wasReconnect) {
console.log('Reestablishment of a connection.');
}
console.log('connected!');
setTimeout(function () {
/*
* Call a Meteor Method
*/
ddpclient.call(
'myMethod', // namyMethodme of Meteor Method being called
['foo', 'bar'], // parameters to send to Meteor Method
function (err, result) { // callback which returns the method call results
console.log('called function, result: ' + result);
ddpclient.close();
},
function () { // callback which fires when server has finished
console.log('updated'); // sending any updated documents as a result of
console.log(ddpclient.collections.posts); // calling this method
}
);
}, 3000);
});
The code assumes that your app runs on localhost:3000, note that there is no conncection close on errors or undesired behavior.
As you can see at the top, the file imports your globally installed ddp package. Now in order to get it's path without using additional tools, just pass an environment variable (process.env.DDP_PATH) and let your shell handle the path resolving.
In order to get the installation path you can use npm root with the global flag.
Finally call your script via:
$ DDP_PATH=$(meteor npm root -g)/ddp meteor node ddptest.js
Which will give you the following output:
connected!
updated
undefined
called function, result: hello result
And logs hello console to the open session that is running your meteor app.
Edit: A note on using this in production
If you want to use this script in production you have to use the shell commands without the meteor command but using your installation of node and npm.
If you get in trouble with paths use process.execPath to find your node binary and npm root -g to find your global npm modules.
You can check out this documentation: Command Line | meteor shell.
While your meteor app is running, you can execute meteor shell to start an interactive console. In the console, you can do Meteor.call(...).
So if you want to write a script with using meteor shell, you might need to pipe the script file for meteor shell. Like,
$ meteor shell < script_file
See also the answer of "How can I pipe a command into the meteor shell?"

Cloud functions for Firebase /usr/bin/env: node not found

My question is: how can I make node available to a shell script on Cloud functions for Firebase when I use an npm package like xml2json?
Context:
I am moving a piece of software from short-living Docker containers to Cloud functions for Firebase. The software processes large XML files and converts parts to JSON.
Due to the memory consumption, I use xmllint and xml2json via the shell.
var cmd = './xmllint --xpath "//OrderData" ' + this.filename + ' | ' + __dirname + '/node_modules/xml2json/bin/xml2json';
exec(cmd, function(error, stdout, stderr) { ... }
Xmllint works as expected (distributed in the npm package that I added to package.json in the functions directory)
"#niekoost/convertini": "file:niekoost-convertini-1.0.1.tgz"
But the pipe through xml2json produces the problem:
The first line of xml2json is causing my issue
#!/usr/bin/env node
This leads to an error in the Cloud Functions log in the Firebase console
Error: Command failed: ./xmllint --xpath "//OrderData"
/tmp/kdjf6kv9hku86xw4h392j4i.xml | /user_code/node_modules/xml2json/bin/xml2json
/usr/bin/env: node: No such file or directory
Where is node located on Cloud functions for Firebase? Can I make it available to /usr/bin/env? Or should I fork the xml2json npm package and change that code.
After some additional searches I have found a solution for my situation, without having to change the npm package that is provided for xml2json.
Since xml2json is used in a command that is being executed by 'exec', we only need to make the path to the Node binary available in the environment of that exec. This path can be derived from 'process.execPath':
var exec = require('child_process').exec;
var process = require('process');
// get path where the node binary is located from within the code that
// is being executed by the node runtime provided by Firebase
var nodePath = process.execPath;
nodePath = nodePath.split('/');
nodePath = nodePath.splice(0, nodePath.length-1).join('/');
// add path to the environment
process.env.PATH += ':' + nodePath;
var cmd = './xmllint --xpath "//OrderData" /xyz.xml | /user_code/node_modules/xml2json/bin/xml2json';
// call the command and provide the extended env
exec(cmd, {env: process.env}, function(error, stdout, stderr) {
...
});

Delete a Firebase Cloud Function which failed with `Deploy Error: undefined`

How can I delete a Firebase Cloud Function which deployed with Deploy Error: undefined?
Steps to reproduce my problem:
1) Create a new Firebase project
2) $ firebase init and setup functions
3) Paste the following code into functions/index.js
"use strict";
const functions = require('firebase-functions');
function aFunction() {
return 'reports/posts';
}
function getCorruptTrigger() {
return '/reports/posts/' + aFunction +'/createdAt'
}
exports.thisFnWillFailToDeploy = functions
.database
.ref(getCorruptTrigger())
.onWrite(event => {});
4) firebase deploy --only functions
5) The function will fail to deploy as expected.
What I tried to delete the Cloud Function:
Removing the function from the index.js and deploying does not delete the function, instead I get functions[thisFnWillFailToDeploy]: Deploy Error: undefined
Deleting the Cloud Function in the Google Cloud Console does not delete the function. (I get a toast saying that the function will be deleted, but this is not the case. In the logs there is an Error with "status":{"code":13})
Creating an empty cloud function with the name thisFnWillFailToDeploy also results in Deploy Error: undefined
That function in your project is in a bad state. Apparently, deploying a function with a malformed ref causes problems with that function that can't be reversed on your own. That function will failed to deploy from the outset (not even having a chance to delete it yet). After that, you can no longer update or delete the function. You'll have to contact support to recover the function, if that's what you need. You should still be able to update or delete other functions in that project.
I'm guessing it's because you have a typo in your function call that generated the name of the ref. You're missing parens on the call to aFunction. I imagine you meant for it to look like this:
function getCorruptTrigger() {
return '/reports/posts/' + aFunction() +'/createdAt'
}
If you deploy that in a new project instead, it should work.

Meteor: EJSON is not defined

I'm trying to use a private JSON file to add some simple template documents to the mongo collection if it is empty:
if (Passions.find().count() === 0) {
mockPassions = JSON.parse(Assets.getText("mockups/passions.json"));
_.each(mockPassions.passions, function(passion) {
return Passions.insert(passion);
});
}
I'm getting the error:
ReferenceError: EJSON is not defined
Does anyone have any clue? I'm using Meteor 0.6.5.
Thanks
You need to bring EJSON up to the global namespace via
meteor add ejson
In meteor 0.6.5 unless you explicitly tell it to, packages are namespaced into package
Considering Latest Meteor 1.6, you can follow below steps:
A. First Approach [Independent of the meteor restart/stop/start]
Edit .meteor/packages file and add 'ejson' to end of the file
B. Second Approach
Stop Server if already running by pressing ctrl+c
Run command meteor add ejson
Restart Server using command meteor

Why does Meteor complain that an insert method for a collection is already defined?

Can anyone tell me why the code below throws the following error? :
Error: A method named '/players/insert' is already defined
I'm new to Meteor and coffeescript so I may be overlooking something simple.
Here's my port of the leaderboard example to coffeescript:
###
Set up a collection to contain player information. On the server,
it is backed by a MongoDB collection named "players."
###
Players = new Meteor.Collection("players")
if Meteor.is_client
Template.leaderboard.players = ->
Players.find({}, {sort: {score: -1, name: 1}})
Template.leaderboard.selected_name = ->
player = Players.findOne(Session.get "selected_player")
player and player.name
Template.player.selected = -> if Session.equals("selected_player", this._id) then "selected" else ''
Template.leaderboard.events = {
'click input.inc': ->
Players.update(Session.get("selected_player"), {$inc: {score: 5}})
}
Template.player.events = {
'click': ->
Session.set("selected_player", this._id)
}
# On server startup, create some players if the database is empty.
if Meteor.is_server
Meteor.startup ->
if Players.find().count() is 0
names = [
"Ada Lovelace"
"Grace Hopper"
"Marie Curie"
"Carl Friedrich Gauss"
"Nikola Tesla"
"Claude Shannon"
]
Players.insert({name: name, score: Math.floor(Math.random()*10)*5}) for name in names
The full stack trace is as follows:
[[[[[ ~/dev/meteor/leaderboard ]]]]]
Running on: http://localhost:3000/
node.js:201
throw e; // process.nextTick error, or 'error' event on first tick
^
Error: A method named '/players/insert' is already defined
at app/packages/livedata/livedata_server.js:744:15
at Function.<anonymous> (app/packages/underscore/underscore.js:84:24)
at [object Object].methods (app/packages/livedata/livedata_server.js:742:7)
at new <anonymous> (app/packages/mongo-livedata/collection.js:111:13)
at app/leaderboard.js:4:11
at /Users/alex/dev/meteor/leaderboard/.meteor/local/build/server/server.js:109:21
at Array.forEach (native)
at Function.<anonymous> (/Users/alex/dev/meteor/leaderboard/.meteor/local/build/server/underscore.js:76:11)
at /Users/alex/dev/meteor/leaderboard/.meteor/local/build/server/server.js:95:7
Exited with code: 1
I'm running Meteor version 0.4.0 (8f4045c1b9)
Thanks in advance for assistance!
You would also get this error, regardless of using coffeescript or plain javascript, if you duplicated your files. For example, copying your sources files to a subdirectory named Backup would produce this error, because Meteor merges files from subdirectories.
This appears to be a configuration issue with coffeelint (installed globally with npm).
I originally installed coffeelint to check that my coffeescript code was correct and had no errors.
I installed coffeelint as per the instructions with:
sudo npm install -g coffeelint
coffeelint worked fine when run stand-alone against .coffee files.
However, when running any Meteor project with coffeescript package added I got the above error.
On a whim, I thought the error might be due to conflict with my exisiting node install.
I decided to uninstall coffeelint first with:
sudo npm uninstall -g coffeelint
and then deleted the previously meteor-generated leaderboard.js file.
After re-starting meteor the coffeescript example above worked as expected without errors.
try moving (ie copying and deleting the original )
Players = new Meteor.Collection("players")
one time below if Meteor.is_client
and another time below if Meteor.is_server
I don't know exactly why, as I'm new to Meteor too, but that worked for me, I assume that the server side needs it's own reference,as well as the client,
although declaring outside the scope should do the same (maybe a bug, remember they're still at 0.5.0 preview , which makes me think you might wanna upgrade and try some new smart packages that are with the new version, it looks like you're using 0.4), but when the files in my server wouldn't recognize anything I defined the root directory of meteor (which pushes these files to both client and server), I defined the server's own reference, and I got the same error, and until I moved the 'public' declaration of the reference to give the server and the client each their own copy, nothing worked.
Hopefully that helps...

Resources