【问题标题】:How to execute mongo commands through shell scripts?如何通过shell脚本执行mongo命令?
【发布时间】: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执行其他命令?

【问题讨论】:

    标签: mongodb bash shell sh


    【解决方案1】:

    您还可以使用--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 :/db --eval "printjson(db.serverStatus())" 或 mongo :/db
    • 谢谢@Gingi - 我的首选方法是mongo mydb --eval "db.users.find({a:'b'}).pretty().shellPrint()" ... simples :)
    • 我希望我能得到所有的结果,而不是看到它被打印出来“输入'it' for more”
    • @Amida 你可以用mongo --eval "db.version()" --quiet 来避免打印你说的所有噪音
    【解决方案2】:

    将您的 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>
    

    【讨论】:

    • 从字面上看.. 您采用与输入到 mongo shell 完全相同的命令,将这些命令保存到 .js 文件,并将其作为参数传递给 mongo 命令。
    • 值得注意的是,当您的脚本(如果提供)执行时,您在 --eval 语句(如果提供)中设置给 mongo 解释器的任何内容都将保留在范围内。您可以使用它使您的脚本更可重用,例如。 mongo --eval "somevar='someval';" db_name script_that_uses_somevar.js
    • @Matt -- 请注意,shell 提供的非 JavaScript 命令在执行的 JavaScript 文件中不可用,因此 use dbNameshow dbs 将在 shell 的内部提示符下工作,但不能从在.js 文件中。非 JavaScript 命令有 JavaScript 等价物,因此这不是限制,只是您需要注意的事项。
    • 如果需要指定数据库名称、用户名、密码,可以mongo dbName -u userName -p "password with spaces" scriptToRun.js
    • 如果您想要动态行为,即传递参数,这不起作用:mongo &lt; demo.js arg1 arg2 arg3 - 您将如何在 js 文件中读取它们?
    【解决方案3】:

    这适用于我在 Linux 下:

    mongo < script.js
    

    【讨论】:

      【解决方案4】:

      把它放在一个名为test.js的文件中:

      db.mycollection.findOne()
      db.getCollectionNames().forEach(function(collection) {
        print(collection);
      });
      

      然后使用mongo myDbName test.js 运行它。

      【讨论】:

      • 如何将值从 bash 传递给脚本?我想将名称插入到 db 中,该名称在 bash 中作为变量可用,我想将其传递给 script(js)
      • 这是一个更好的解决方案,当我将文件通过管道传输到 mongo 时,会出现 js 语法错误。
      • 循环内部,其他命令不执行。
      【解决方案5】:

      还有一个关于此的official documentation 页面。

      该页面的示例包括:

      mongo server:27017/dbname --quiet my_commands.js
      mongo test --eval "printjson(db.getCollectionNames())"
      

      【讨论】:

        【解决方案6】:

        下面的 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
        • 绝对有用,因为您不能在 JS 文件中使用“使用 mydb”。
        • 谢谢你!最后我可以打电话给use another_db。 :-)
        • 其实你可以在 mongo 脚本中切换 DB:db = db.getSiblingDB('otherdb');
        • 正是我所需要的。但是,如果您只需要使用一个数据库,您可以将数据库名称传递给 mongo 命令,例如mongo mydb &lt;&lt;EOF
        【解决方案7】:

        我使用 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>
        

        这个解决方案有几个问题:

        1. 仅当您尝试使 mongo shell 脚本从命令行执行时才有效。您不能将常规 shell 命令与 mongo shell 命令混合使用。而且您这样做所节省的只是不必在命令行上键入“mongo”......(当然,这很合理)

        2. 它的功能与“mongo ”完全相同,这意味着它不允许您使用“use ”命令。

        我已尝试将数据库名称添加到 shebang,您认为这会起作用。不幸的是,系统处理 shebang 行的方式,第一个空格之后的所有内容都作为单个参数(就像引用一样)传递给 env 命令,并且 env 无法找到并运行它。

        相反,您必须将数据库更改嵌入脚本本身,如下所示:

        #!/bin/env mongo
        db = db.getSiblingDB('<db>');
        <your script>
        

        就像生活中的任何事情一样,“有不止一种方法可以做到!”

        【讨论】:

        • 如果你引用你的 HEREDOC 定界符,shell 将不会解释或替换任何东西,例如代替 blah blah
        • 这是一个很好的答案!如何将 shell 变量传递给查询?
        • 答案是不要逃避你的HEREDOC。然后,您将能够在其中进行替换。关键是,您必须避开任何文字美元符号。
        【解决方案8】:

        如果您启用了身份验证:

        mongo -u username -p password --authenticationDatabase auth_db_name < your_script.js
        

        【讨论】:

          【解决方案9】:

          在我的设置中我必须使用:

          mongo --host="the.server.ip:port" databaseName theScript.js 
          

          【讨论】:

            【解决方案10】:

            这个怎么样:

            echo "db.mycollection.findOne()" | mongo myDbName
            echo "show collections" | mongo myDbName
            

            【讨论】:

            • 或者更具可读性:echo "db.mycollection.findOne()" | mongo myDbName --quiet | python -m json.tool
            • 这对于在 .mongorc 加载后执行某些操作很有用 (docs.mongodb.org/manual/reference/program/mongo/…)
            • 我可以把结果放在 shell 的变量中吗?
            【解决方案11】:

            创建一个脚本文件;写命令:

            #!/bin/sh
            mongo < file.js
            

            file.js 中写下你的 mongo 查询:

            db.collection.find({"myValue":null}).count();
            

            【讨论】:

              【解决方案12】:

              正如theTuxRacer 所建议的,您可以使用 eval 命令,对于像我一样缺少它的人,如果您不尝试执行操作,也可以添加您的数据库名称在默认数据库上。

              mongo <dbname> --eval "printjson(db.something.find())"
              

              【讨论】:

                【解决方案13】:

                谢谢printf!在 Linux 环境中,这里有一种更好的方法,可以只让一个文件运行该节目。假设你有两个文件,mongoCmds.js 有多个命令:

                use someDb
                db.someColl.find()
                

                然后是驱动程序外壳文件,runMongoCmds.sh

                mongo < mongoCmds.js
                

                相反,只有一个文件 runMongoCmds.sh 包含

                printf "use someDb\ndb.someColl.find()" | mongo
                

                Bash 的 printfecho 更健壮,并且允许命令之间的 \n 强制它们在多行上。

                【讨论】:

                  【解决方案14】:

                  在我的例子中,我可以方便地使用\n 作为我要执行的下一个 mongo 命令的分隔符,然后将它们通过管道传送到mongo

                  echo $'use your_db\ndb.yourCollection.find()' | mongo
                  

                  【讨论】:

                    【解决方案15】:
                    mongo <<EOF
                    use <db_name>
                    db.getCollection("<collection_name>").find({})
                    EOF
                    

                    【讨论】:

                      【解决方案16】:

                      --shell 标志也可用于 javascript 文件

                       mongo --shell /path/to/jsfile/test.js 
                      

                      【讨论】:

                      • 我认为这只是在 js 执行后让 shell 保持打开状态? mongo /path/to/jsfile/test.js 也会执行 js。
                      【解决方案17】:
                      mongo db_name --eval "db.user_info.find().forEach(function(o) {print(o._id);})"
                      

                      【讨论】:

                        【解决方案18】:

                        最近从 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? 这不是题外话。事实上,由于标题,我提出了这个问题。所以像我这样的人会受益于阅读这样的答案。另外,我在示例中给出了一个非常有用的方法,而不是一个玩具示例。
                        【解决方案19】:

                        如果您想用一条线处理它,这是一种简单的方法。

                        file.sh --> db.EXPECTED_COLLECTION.remove("_id":1234)
                        
                        cat file.sh | mongo <EXPECTED_COLLECTION>
                        

                        【讨论】:

                          【解决方案20】:

                          能够传递 mongo 参数(--quiet、dbname 等)的单 shell 脚本解决方案:

                          #!/usr/bin/env -S mongo --quiet localhost:27017/test
                          
                          cur = db.myCollection.find({});
                          while(cur.hasNext()) {
                            printjson(cur.next());
                          }
                          

                          -S 标志可能不适用于所有平台。

                          【讨论】:

                            【解决方案21】:

                            当使用副本集时,必须在 PRIMARY 上进行写入,所以我通常使用这样的语法来避免必须确定哪个主机是主服务器:

                            mongo -host myReplicaset/anyKnownReplica

                            【讨论】:

                              猜你喜欢
                              • 2015-11-01
                              • 1970-01-01
                              • 1970-01-01
                              • 2019-11-06
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 2018-10-06
                              相关资源
                              最近更新 更多