【发布时间】:2011-06-17 18:49:00
【问题描述】:
我想在 shell 脚本中执行mongo 命令,例如在脚本中test.sh:
#!/bin/sh
mongo myDbName
db.mycollection.findOne()
show collections
当我通过./test.sh执行这个脚本时,与MongoDB的连接就建立了,但是下面的命令并没有被执行。
如何通过shell脚本test.sh执行其他命令?
【问题讨论】:
我想在 shell 脚本中执行mongo 命令,例如在脚本中test.sh:
#!/bin/sh
mongo myDbName
db.mycollection.findOne()
show collections
当我通过./test.sh执行这个脚本时,与MongoDB的连接就建立了,但是下面的命令并没有被执行。
如何通过shell脚本test.sh执行其他命令?
【问题讨论】:
您还可以使用--eval 标志来评估一个命令,如果它只是一个命令。
mongo --eval "printjson(db.serverStatus())"
请注意:如果您使用 Mongo 运算符,以 $ 符号开头,您需要将 eval 参数括在单引号中,以防止 shell 将运算符视为环境变量:
mongo --eval 'db.mycollection.update({"name":"foo"},{$set:{"this":"that"}});' myDbName
否则您可能会看到如下内容:
mongo --eval "db.test.update({\"name\":\"foo\"},{$set:{\"this\":\"that\"}});"
> E QUERY SyntaxError: Unexpected token :
【讨论】:
.find()操作,需要在结果对象上调用操作来打印文档,如toArray()或shellPrint()。例如,mongo userdb --eval "printjson(db.users.find().toArray())"
mongo mydb --eval "db.users.find({a:'b'}).pretty().shellPrint()" ... simples :)
mongo --eval "db.version()" --quiet 来避免打印你说的所有噪音
将您的 mongo 脚本放入 .js 文件中。
然后执行mongo < yourFile.js
例如:
demo.js //文件有你的脚本
use sample //db name
show collections
将此文件保存在“c:\db-scripts”中
然后在 cmd 提示符下转到“c:\db-scripts”
C:\db-scripts>mongo < demo.js
这将在 mongo 中执行代码并显示输出
C:\db-scripts>mongo < demo.js
Mongo shell version: 3.0.4
Connecting to: test
switched to db sample
users //collection name
tasks //collection name
bye
C:\db-scripts>
【讨论】:
.js 文件,并将其作为参数传递给 mongo 命令。
use dbName 和 show dbs 将在 shell 的内部提示符下工作,但不能从在.js 文件中。非 JavaScript 命令有 JavaScript 等价物,因此这不是限制,只是您需要注意的事项。
mongo dbName -u userName -p "password with spaces" scriptToRun.js
mongo < demo.js arg1 arg2 arg3 - 您将如何在 js 文件中读取它们?
这适用于我在 Linux 下:
mongo < script.js
【讨论】:
把它放在一个名为test.js的文件中:
db.mycollection.findOne()
db.getCollectionNames().forEach(function(collection) {
print(collection);
});
然后使用mongo myDbName test.js 运行它。
【讨论】:
还有一个关于此的official documentation 页面。
该页面的示例包括:
mongo server:27017/dbname --quiet my_commands.js
mongo test --eval "printjson(db.getCollectionNames())"
【讨论】:
下面的 shell 脚本对我也很有效...肯定必须使用 Antonin 最初提到的重定向...这让我有了测试这里文档的想法。
function testMongoScript {
mongo <<EOF
use mydb
db.leads.findOne()
db.leads.find().count()
EOF
}
【讨论】:
echo -e "use mydb\ndb.leads.findOne()\ndb.leads.find().count()" | mongo
use another_db。 :-)
db = db.getSiblingDB('otherdb');
mongo mydb <<EOF等
我使用 David Young 提到的“heredoc”语法。但有一个问题:
#!/usr/bin/sh
mongo <db> <<EOF
db.<collection>.find({
fieldName: { $exists: true }
})
.forEach( printjson );
EOF
上面的方法不起作用,因为短语“$exists”将被 shell 看到并替换为名为“exists”的环境变量的值。这很可能是不存在的,所以在shell扩展之后,它变成了:
#!/usr/bin/sh
mongo <db> <<EOF
db.<collection>.find({
fieldName: { : true }
})
.forEach( printjson );
EOF
为了让它通过你有两个选择。一个很丑,一个很好看。首先,丑陋的:避开 $ 符号:
#!/usr/bin/sh
mongo <db> <<EOF
db.<collection>.find({
fieldName: { \$exists: true }
})
.forEach( printjson );
EOF
我不推荐这样做,因为很容易忘记逃跑。
另一种选择是转义 EOF,如下所示:
#!/usr/bin/sh
mongo <db> <<\EOF
db.<collection>.find({
fieldName: { $exists: true }
})
.forEach( printjson );
EOF
现在,您可以将所需的所有美元符号放在 heredoc 中,而美元符号将被忽略。不利的一面:如果您需要将 shell 参数/变量放在 mongo 脚本中,这将不起作用。
你可以玩的另一个选择是搞乱你的shebang。例如,
#!/bin/env mongo
<some mongo stuff>
这个解决方案有几个问题:
仅当您尝试使 mongo shell 脚本从命令行执行时才有效。您不能将常规 shell 命令与 mongo shell 命令混合使用。而且您这样做所节省的只是不必在命令行上键入“mongo”......(当然,这很合理)
它的功能与“mongo
我已尝试将数据库名称添加到 shebang,您认为这会起作用。不幸的是,系统处理 shebang 行的方式,第一个空格之后的所有内容都作为单个参数(就像引用一样)传递给 env 命令,并且 env 无法找到并运行它。
相反,您必须将数据库更改嵌入脚本本身,如下所示:
#!/bin/env mongo
db = db.getSiblingDB('<db>');
<your script>
就像生活中的任何事情一样,“有不止一种方法可以做到!”
【讨论】:
如果您启用了身份验证:
mongo -u username -p password --authenticationDatabase auth_db_name < your_script.js
【讨论】:
在我的设置中我必须使用:
mongo --host="the.server.ip:port" databaseName theScript.js
【讨论】:
这个怎么样:
echo "db.mycollection.findOne()" | mongo myDbName
echo "show collections" | mongo myDbName
【讨论】:
.mongorc 加载后执行某些操作很有用 (docs.mongodb.org/manual/reference/program/mongo/…)
创建一个脚本文件;写命令:
#!/bin/sh
mongo < file.js
在file.js 中写下你的 mongo 查询:
db.collection.find({"myValue":null}).count();
【讨论】:
正如theTuxRacer 所建议的,您可以使用 eval 命令,对于像我一样缺少它的人,如果您不尝试执行操作,也可以添加您的数据库名称在默认数据库上。
mongo <dbname> --eval "printjson(db.something.find())"
【讨论】:
谢谢printf!在 Linux 环境中,这里有一种更好的方法,可以只让一个文件运行该节目。假设你有两个文件,mongoCmds.js 有多个命令:
use someDb
db.someColl.find()
然后是驱动程序外壳文件,runMongoCmds.sh
mongo < mongoCmds.js
相反,只有一个文件 runMongoCmds.sh 包含
printf "use someDb\ndb.someColl.find()" | mongo
Bash 的 printf 比 echo 更健壮,并且允许命令之间的 \n 强制它们在多行上。
【讨论】:
在我的例子中,我可以方便地使用\n 作为我要执行的下一个 mongo 命令的分隔符,然后将它们通过管道传送到mongo
echo $'use your_db\ndb.yourCollection.find()' | mongo
【讨论】:
mongo <<EOF
use <db_name>
db.getCollection("<collection_name>").find({})
EOF
【讨论】:
--shell 标志也可用于 javascript 文件
mongo --shell /path/to/jsfile/test.js
【讨论】:
mongo /path/to/jsfile/test.js 也会执行 js。
mongo db_name --eval "db.user_info.find().forEach(function(o) {print(o._id);})"
【讨论】:
最近从 mongodb 迁移到 Postgres。这就是我使用脚本的方式。
mongo < scripts.js > inserts.sql
读取scripts.js并将输出重定向到inserts.sql。
scripts.js 看起来像这样
use myDb;
var string = "INSERT INTO table(a, b) VALUES";
db.getCollection('collectionName').find({}).forEach(function (object) {
string += "('" + String(object.description) + "','" + object.name + "'),";
});
print(string.substring(0, string.length - 1), ";");
inserts.sql 看起来像这样
INSERT INTO table(a, b) VALUES('abc', 'Alice'), ('def', 'Bob'), ('ghi', 'Claire');
【讨论】:
How to execute mongo commands through shell scripts? 这不是题外话。事实上,由于标题,我提出了这个问题。所以像我这样的人会受益于阅读这样的答案。另外,我在示例中给出了一个非常有用的方法,而不是一个玩具示例。
如果您想用一条线处理它,这是一种简单的方法。
file.sh --> db.EXPECTED_COLLECTION.remove("_id":1234)
cat file.sh | mongo <EXPECTED_COLLECTION>
【讨论】:
能够传递 mongo 参数(--quiet、dbname 等)的单 shell 脚本解决方案:
#!/usr/bin/env -S mongo --quiet localhost:27017/test
cur = db.myCollection.find({});
while(cur.hasNext()) {
printjson(cur.next());
}
-S 标志可能不适用于所有平台。
【讨论】:
当使用副本集时,必须在 PRIMARY 上进行写入,所以我通常使用这样的语法来避免必须确定哪个主机是主服务器:
mongo -host myReplicaset/anyKnownReplica
【讨论】: