上一篇文章说了MongoDB一些常用的更新操作,这篇就来写写常用的查询操作。
最基本的查询就莫过于,我们之前的findOne()和find()了。基本上已经非常熟悉了,但是我们在后面会慢慢探讨findOne和find的多种多样的查询方式。先来简单的回忆一下
db.product.findOne();
db.product.find();
db.product.find({product_name:"iPhoneX"});
在我们的查询中好像只有=的匹配,就没有别的了。下面我们看看其他的查询条件
"$lt" 小于 "$lte"小于等于 "$gt" 大于 "$gte" 大于等于 $ne 不等于
下面的例子,我们查询商品价格大于5000元的商品:
db.product.find({price:{$gte:5000}});
查询上架日期为2017年10月的
db.product.find({create_date:{$gte:new Date("2017-10-01")},create_date:{$lt:new Date("2017-11-01")}});
查询不是官方自营店的iPhone X商品
db.product.find({store:{$ne:"官方自营店"}});
目前我们的所有查询都是AND形式去组合条件查询,后面会通过一些操作符实现其他形式的组合查询。
在SQL当中,我们可以在select 关键字后面指定要返回数据字段。MongoDB也可以实现类似的功能。
我们可以通过find方法的第二个参数指定我们需要返回什么字段,或者指定不返回什么字段
db.product.find({product_name:"iPhoneX"},{product_name:1,price:1,brand:1,store:1});
我们通过第二个参数,指定了我们需要显示那几个字段。你会看到在find第二个参数当中,字段属性的值都是1,代表显示,如果是0代表不显示。需要注意的是,默认_id就算没有指定显示也会自动显示,当然你可以显性指定为不显示
结果:
{
"_id" : ObjectId("59e47fdb203e071a1b02e544"),
"product_name" : "iPhoneX",
"price" : 8699.0,
"brand" : "Apple",
"store" : "官方自营店"
}
{
"_id" : ObjectId("59e5a20f7dfc75087c893b50"),
"product_name" : "iPhoneX",
"price" : 8699.0,
"brand" : "Apple",
"store" : "第三方渠道"
}
我们也可以指定不现实那几个字段属性:
db.product.find({product_name:"iPhoneX"},{_id:0,size:0,newest_commment:0,sku:0,popular_comment:0,keyword:0,create_date:0});
显示结果如下:
{
"product_name" : "iPhoneX",
"price" : 8699.0,
"description" : "一台贵到666的手机",
"product_number" : "9088816371",
"brand" : "Apple",
"store" : "官方自营店"
}
{
"product_name" : "iPhoneX",
"price" : 8699.0,
"description" : "一台贵到666的手机",
"product_number" : "9088816371",
"brand" : "Apple",
"store" : "第三方渠道"
}
上面我们所有的组合查询都是AND方式去查询,我们可以通过$in、$nin 或者 $or 操作符去进行OR方式的组合查询
为了测试,我们创建一个用户collection,然后通过手机号码通过$in获得用户数据:
var userA = {username:"TONY",user_pic:"default.jpg",phone_number:"13333333338"};
var userB = {username:"YAN", user_pic:"default.jpg",phone_number:"13888888883"};
db.user.insert(userA);
db.user.insert(userB);
db.user.find({"phone_number":{$in:["13333333338","13888888883"]}});
返回的结果:
{
"_id" : ObjectId("59e800722d68f77114ec4fac"),
"username" : "TONY",
"user_pic" : "default.jpg",
"phone_number" : "13333333338"
}
{
"_id" : ObjectId("59e800822d68f77114ec4fad"),
"username" : "YAN",
"user_pic" : "default.jpg",
"phone_number" : "13888888883"
}
当然我们还可以使用 $nin 不包含在数值的匹配条件都查询出来
var userA = {username:"TONY",user_pic:"default.jpg",phone_number:"13333333338"};
var userB = {username:"YAN", user_pic:"default.jpg",phone_number:"13888888883"};
var userC = {username:"CHAO",user_pic:"default.jpg",phone_number:"18333333338"};
var userD = {username:"HONO",user_pic:"default.jpg",phone_number:"18888888883"};
db.user.insert(userA);
db.user.insert(userB);
db.user.insert(userC);
db.user.insert(userD);
db.user.find({"phone_number":{$nin:["13333333338","13888888883"]}});
返回的结果:
{
"_id" : ObjectId("59e802432d68f77114ec4fae"),
"username" : "CHAO",
"user_pic" : "default.jpg",
"phone_number" : "18333333338"
}
{
"_id" : ObjectId("59e802442d68f77114ec4faf"),
"username" : "HONO",
"user_pic" : "default.jpg",
"phone_number" : "18888888883"
}
(username = "TONY" OR phone_number = "18888888883") AND user_pic = "default.jpg"
db.user.find({$or:[{"username":"TONY"},{"phone_number":"18888888883"}],"user_pic":"default.jpg"});
{
"_id" : ObjectId("59e800722d68f77114ec4fac"),
"username" : "TONY",
"user_pic" : "default.jpg",
"phone_number" : "13333333338"
}
{
"_id" : ObjectId("59e802442d68f77114ec4faf"),
"username" : "HONO",
"user_pic" : "default.jpg",
"phone_number" : "18888888883"
}
除了一个$or 还有一个$nor。就是取反:
db.user.find({$nor:[{"phone_number":"18888888883"},{"username":"YAN"}]});
{
"_id" : ObjectId("59e800722d68f77114ec4fac"),
"username" : "TONY",
"user_pic" : "default.jpg",
"phone_number" : "13333333338"
}
{
"_id" : ObjectId("59e802432d68f77114ec4fae"),
"username" : "CHAO",
"user_pic" : "default.jpg",
"phone_number" : "18333333338"
}
这个比较难解释,这个跟上面OR小节有比较大的关系。可以在其他任意条件之前去做取反操作,打个比方:
db.user.find({"phone_number":{$not:{$in:["18888888883","13333333338"]}}});
搜索结果如下:
{
"_id" : ObjectId("59e800822d68f77114ec4fad"),
"username" : "YAN",
"user_pic" : "default.jpg",
"phone_number" : "13888888883"
}
{
"_id" : ObjectId("59e802432d68f77114ec4fae"),
"username" : "CHAO",
"user_pic" : "default.jpg",
"phone_number" : "18333333338"
}
对于null这种空值处理还是比较麻烦的,因为再MongoDB不像SQL每一行记录的数据格式都是固定的。笔者在SpringCloud的微服务项目当中,通过MongoDB repository 去添加文档,如果为null 的字段,根本就不会把改字段属性添加到MongoDB当中。所以除了去判断空值,还需要去判断字段属性(KEY)是否存在。
为了测试,我为已经存在的user collection当中添加gender字段属性。我不会全部添加,部分我们添加gender的key但是写上null,还有一些我不会去添加gender的key。【其实,在MongoDB当中,字段属性是不太正确的做法,但是作为一个SQL的资深用户,为了好理解一直这样说,后面我会改成KEY 或者 键】
var tony = db.user.findOne({"username":"TONY"});
tony.gender = "male";
db.user.save(tony);
var yan = db.user.findOne({"username":"YAN"});
yan.gender = "male";
db.user.save(yan);
var chao = db.user.findOne({"username":"CHAO"});
chao.gender = null;
db.user.save(chao);
db.user.find();
{
"_id" : ObjectId("59e83a2d2d68f77114ec4fb4"),
"username" : "TONY",
"user_pic" : "default.jpg",
"phone_number" : "13333333338",
"gender" : "male"
}
{
"_id" : ObjectId("59e83a2d2d68f77114ec4fb5"),
"username" : "YAN",
"user_pic" : "default.jpg",
"phone_number" : "13888888883",
"gender" : "male"
}
{
"_id" : ObjectId("59e83a2e2d68f77114ec4fb6"),
"username" : "CHAO",
"user_pic" : "default.jpg",
"phone_number" : "18333333338",
"gender" : null
}
{
"_id" : ObjectId("59e83a2f2d68f77114ec4fb7"),
"username" : "HONO",
"user_pic" : "default.jpg",
"phone_number" : "18888888883"
}
db.user.find({gender:null});
我们通过上面的查询可以同时获得HONO 和 CHAO 两个用户,可能是版本的原因。在以前的旧版本当中是无法使用上面的查询的。
我们可以使用$exists 获得不存在gender 的用户
db.user.find({gender:{$exists:false}});
MongoDB最为方便的查询就莫过于正则表达式查询了。我们可以通过MongoDB的正则表达式查询实现如SQL的LIKE模糊查询
db.user.find({username:/O/i});
查询结果:
{
"_id" : ObjectId("59e83a2d2d68f77114ec4fb4"),
"username" : "TONY",
"user_pic" : "default.jpg",
"phone_number" : "13333333338",
"gender" : "male"
}
{
"_id" : ObjectId("59e83a2e2d68f77114ec4fb6"),
"username" : "CHAO",
"user_pic" : "default.jpg",
"phone_number" : "18333333338",
"gender" : null
}
{
"_id" : ObjectId("59e83a2f2d68f77114ec4fb7"),
"username" : "HONO",
"user_pic" : "default.jpg",
"phone_number" : "18888888883"
}
首先我们通过一个普通的查询,看看MongoDB数组的查询是怎么样的:
db.product.find({"keyword":"iphone"},{"product_name":1,"keyword":1,"price":1,"store":1});
结果可以发现,只要keyword数组当中,有iphone 就匹配上。
{
"_id" : ObjectId("59e47fdb203e071a1b02e544"),
"product_name" : "iPhoneX",
"price" : 8699.0,
"keyword" : [
"苹果",
"iphone",
"apple"
],
"store" : "官方自营店"
}
{
"_id" : ObjectId("59e5a20f7dfc75087c893b50"),
"product_name" : "iPhoneX",
"price" : 8699.0,
"keyword" : [
"苹果",
"iphone",
"apple"
],
"store" : "第三方渠道"
}
但是事实上却没有我们想象中这么方便,如我们希望在一个数组属性当中同时匹配其中两个关键字的话,上面的方法就不是这么奏效了。
看看下面的列子:
var userA = {username:"TONY",user_pic:"default.jpg",phone_number:"13333333338",favorite:["swimming","computer game","reading","running"]};
var userB = {username:"YAN", user_pic:"default.jpg",phone_number:"13888888883",favorite:["football","drawing","video game","shopping"]};
var userC = {username:"CHAO", user_pic:"default.jpg",phone_number:"13888888889",favorite:["talking show","swimming","computer game","kidding"]};
var userD = {username:"LTT", user_pic:"default.jpg",phone_number:"13888888833",favorite:["shopping","watching tv","running","travel"]};
db.user.insert(userA);
db.user.insert(userB);
db.user.insert(userC);
db.user.insert(userD);
db.user.find({favorite:["swimming","reading"]});
结果将会返回空,因为上面这条语句会精确匹配只有两个元素而且是swimming 和 reading的文档结果。最重要的是,精确匹配会连顺序都要完全匹配。
如果希望在一个数组当中同时匹配到指定的元素,我们可以使用$all 操作符。(匹配跟顺序无关)
db.user.find({favorite:{$all : ["swimming","reading"]}});
返回结果:
{
"_id" : ObjectId("59eb577e89c5ddc1ad8058b6"),
"username" : "TONY",
"user_pic" : "default.jpg",
"phone_number" : "13333333338",
"favorite" : [
"swimming",
"computer game",
"reading",
"running"
]
}
db.user.find({"favorite.1":"drawing"});
{
"_id" : ObjectId("59eb577f89c5ddc1ad8058b7"),
"username" : "YAN",
"user_pic" : "default.jpg",
"phone_number" : "13888888883",
"favorite" : [
"football",
"drawing",
"video game",
"shopping"
]
}
db.user.find({"favorite":{$size:4}});
我们希望返回用户的前两个favorite
db.user.find({"username":"TONY"},{username:1,phone_number:1,favorite:{$slice:2}});
{
"_id" : ObjectId("59eb577e89c5ddc1ad8058b6"),
"username" : "TONY",
"phone_number" : "13333333338",
"favorite" : [
"reading",
"running"
]
}
如果希望返回最后两个favorite元素,将2改成-1即可。
最牛逼的还是可以截取中间指定范围的子数组:
db.user.find({"username":"TONY"},{username:1,phone_number:1,favorite:{$slice:[1,2]}});
返回结果:
{
"_id" : ObjectId("59eb577e89c5ddc1ad8058b6"),
"username" : "TONY",
"phone_number" : "13333333338",
"favorite" : [
"computer game",
"reading"
]
}
db.user.find({"username":"TONY"},{favorite:{$slice:[1,2]}});
返回结果:
{
"_id" : ObjectId("59eb577e89c5ddc1ad8058b6"),
"username" : "TONY",
"user_pic" : "default.jpg",
"phone_number" : "13333333338",
"favorite" : [
"computer game",
"reading"
]
}
有时候我们不知道我们想要的数组元素具体的下标,我们可以通过查询的方位去定位到某一个数组元素:
db.product.findOne({"popular_comment.user_id":119},{"popular_comment.$":1});
返回结果
{
"_id" : ObjectId("59e47fdb203e071a1b02e544"),
"popular_comment" : [
{
"content" : "Comment C content !",
"user_id" : 119.0,
"popularity_degree" : 108.0
}
]
}
来看看下面的查询例子:
db.product.update({"store":"官方自营店"},{$set:{"sku.0.price":8388,"sku.1.price":8388,"sku.2.price":9688,"sku.3.price":9688}});
db.product.findOne({"store":"官方自营店"});
db.product.update({"store":"第三方渠道"},{$set:{"sku.0.price":9600,"sku.1.price":9800,"sku.2.price":12388,"sku.3.price":12699}});
db.product.findOne({"store":"第三方渠道"});
db.product.update({"store":"金牌苹果店"},{$set:{"sku.0.price":9500,"sku.1.price":9600,"sku.2.price":12388,"sku.3.price":12588}});
db.product.findOne({"store":"金牌苹果店"});
db.product.find({"sku.price":{$gt:9850,$lt:10000}});
按照道理来说,应该查询不出任何数据的,因为9850-10000这个区间之内,根本没有任何一个数组的元素可以匹配上。但是事实上mo'nMongoDB返回了以下的数据:
{
"_id" : ObjectId("59e5a20f7dfc75087c893b50"),
"product_name" : "iPhoneX",
"price" : 8699.0,
"description" : "一台贵到666的手机",
"product_number" : "9088816371",
"brand" : "Apple",
"size" : "143.6 X 70.9",
"newest_commment" : {
"comment_content" : "this is newtest comment at that place!",
"user_id" : 109382.0,
"create_date" : ISODate("2017-10-17T01:15:20.466+0000")
},
"sku" : [
{
"capacity" : "64G",
"style" : "silver",
"price" : 9600.0
},
{
"capacity" : "64G",
"style" : "gray",
"price" : 9800.0
},
{
"capacity" : "256G",
"style" : "silver",
"price" : 12388.0
},
{
"capacity" : "256G",
"style" : "gray",
"price" : 12699.0
}
],
"popular_comment" : [
{
"content" : "Comment A content !",
"user_id" : 399.0,
"popularity_degree" : 89.0
},
{
"content" : "Comment C content !",
"user_id" : 119.0,
"popularity_degree" : 108.0
},
{
"content" : "Comment E content !",
"user_id" : 893.0,
"popularity_degree" : 103.0
}
],
"keyword" : [
"苹果",
"iphone",
"apple"
],
"store" : "第三方渠道",
"create_date" : ISODate("2017-11-10T00:00:00.000+0000")
}
{
"_id" : ObjectId("59e9c5872d68f77114ec4fb8"),
"product_name" : "iPhoneX",
"price" : 8699.0,
"description" : "一台贵到666的手机",
"product_number" : "9088816371",
"brand" : "Apple",
"size" : "143.6 X 70.9",
"newest_commment" : {
"comment_content" : "this is newtest comment at that place!",
"user_id" : 109382.0,
"create_date" : ISODate("2017-10-17T01:15:20.466+0000")
},
"sku" : [
{
"capacity" : "64G",
"style" : "silver",
"price" : 9500.0
},
{
"capacity" : "64G",
"style" : "gray",
"price" : 9600.0
},
{
"capacity" : "256G",
"style" : "silver",
"price" : 12388.0
},
{
"capacity" : "256G",
"style" : "gray",
"price" : 12588.0
}
],
"popular_comment" : [
{
"content" : "Comment A content !",
"user_id" : 399.0,
"popularity_degree" : 89.0
},
{
"content" : "Comment C content !",
"user_id" : 119.0,
"popularity_degree" : 108.0
},
{
"content" : "Comment E content !",
"user_id" : 893.0,
"popularity_degree" : 103.0
}
],
"keyword" : [
"iphone"
],
"store" : "金牌苹果店",
"create_date" : ISODate("2017-11-10T00:00:00.000+0000")
}
可以看到的是,有两条数据。因为MongoDB会查询文档中sku数组中的其中有元素大于9850,并且其中有元素小于10000即可。但是必须有一个元素满足大于9850和必须有一个元素小于10000,那这里就会匹配以上的两条数据。但是官方自营店的数据却匹配不上去了。因为官方自营店无法满足有元素大约9850这个匹配条件。
所以我们可以使用$elemMatch这个操作符进行组合条件匹配操作,但是需要注意的是,$elemMatch无法匹配非数组的key
db.product.find({"sku.price":{$elemMatch:{$gt:9850,$lt:10000}}});
此时查询就会返回空
$where 查询是一种非常消耗资源的查询方法,当所有操作符无法达成你的查询要求时,就可以使用$where。但是$where 不走索引,查询速度会怎么样大家应该也很清楚了。所以如无必要就不用使用它。以下我们通过以下查询演示一下$where的查询方法。
db.product.find({$where:function(){
if(this.store == "官方自营店"){
return true;
}
return false;
}});
查询与db.product.find({store:"官方自营店"})等价,我们可以看见$where查询非常灵活,因为查询是通过JavaScript进行的,所以方便直接。但是查询速度是个大问题,所以一般情况下,我们会先用普通的操作符进行初步筛选,然后再通过$where进行二次筛选,这样的话查询速度会比较可控。关于这种查询会在之后的文章中介绍。
在SQL当中排序和分页查询应该算是使用率比较高的一个操作了,在MongoDB当中,分页查询也是相当的重要。下面通过skip limit sort方法去实现分页排序查询。
db.product.find().skip(1).limit(2).sort({"sku.0.price":-1});
查询一开始先通过skip跳开第一行数据,然后限制返回2条数据,查询通过商品的第一个sku的价格进行倒列排序(如果我们需要正序排序将-1改成1即可),返回的结果如下:
{
"_id" : ObjectId("59e9c5872d68f77114ec4fb8"),
"product_name" : "iPhoneX",
"price" : 8699.0,
"description" : "一台贵到666的手机",
"product_number" : "9088816371",
"brand" : "Apple",
"size" : "143.6 X 70.9",
"newest_commment" : {
"comment_content" : "this is newtest comment at that place!",
"user_id" : 109382.0,
"create_date" : ISODate("2017-10-17T01:15:20.466+0000")
},
"sku" : [
{
"capacity" : "64G",
"style" : "silver",
"price" : 9500.0
},
{
"capacity" : "64G",
"style" : "gray",
"price" : 9600.0
},
{
"capacity" : "256G",
"style" : "silver",
"price" : 12388.0
},
{
"capacity" : "256G",
"style" : "gray",
"price" : 12588.0
}
],
"popular_comment" : [
{
"content" : "Comment A content !",
"user_id" : 399.0,
"popularity_degree" : 89.0
},
{
"content" : "Comment C content !",
"user_id" : 119.0,
"popularity_degree" : 108.0
},
{
"content" : "Comment E content !",
"user_id" : 893.0,
"popularity_degree" : 103.0
}
],
"keyword" : [
"iphone"
],
"store" : "金牌苹果店",
"create_date" : ISODate("2017-11-10T00:00:00.000+0000")
}
{
"_id" : ObjectId("59e47fdb203e071a1b02e544"),
"product_name" : "iPhoneX",
"price" : 8699.0,
"description" : "一台贵到666的手机",
"product_number" : "9088816371",
"brand" : "Apple",
"size" : "143.6 X 70.9",
"newest_commment" : {
"comment_content" : "this is newtest comment at that place!",
"user_id" : 109382.0,
"create_date" : ISODate("2017-10-17T01:15:20.466+0000")
},
"sku" : [
{
"capacity" : "64G",
"style" : "silver",
"price" : 8388.0
},
{
"capacity" : "64G",
"style" : "gray",
"price" : 8388.0
},
{
"capacity" : "256G",
"style" : "silver",
"price" : 9688.0
},
{
"capacity" : "256G",
"style" : "gray",
"price" : 9688.0
}
],
"popular_comment" : [
{
"content" : "Comment A content !",
"user_id" : 399.0,
"popularity_degree" : 89.0
},
{
"content" : "Comment C content !",
"user_id" : 119.0,
"popularity_degree" : 108.0
},
{
"content" : "Comment E content !",
"user_id" : 893.0,
"popularity_degree" : 103.0
}
],
"keyword" : [
"苹果",
"iphone",
"apple"
],
"store" : "官方自营店",
"create_date" : ISODate("2017-10-27T00:00:00.000+0000")
}
其实使用skip进行分页查询是最为方便的一个做法,但是事实上skip的查询效率上并不高。skip需要先找到需要跳过的数据文档,然后进行丢弃,这个已经足够低效了。如果数据量大的话通过skip进行查询将不会是一个好的策略。我们可以利用一些关键的key,然后通过$gt或者$lt的方式进行跳过的操作。
举个例子
var pageOne = db.product.find().limit(1).sort({"sku.0.price":1});
var firstItem = pageOne.next();
db.product.find({"sku.0.price":{$gt:firstItem.sku[0].price}}).limit(1).sort({"sku.0.price":1});
可以看见我们是通过游标pageOne,获得第一页最后一个对象,然后通过改对象的价格属性进行$gt条件查询,再通过limit进行限制。重点是两条查询语句必须要使用价格属性进行排序。如果是有两个同样的价格这样就不太奏效了,所以也不是万能的一个方式。
其实第13点已经使用了游标了,就是那个pageOne。游标跟我们以前SQL的游标其实差不多,MongoDB的游标在find方法执行完之后会返回,但是不会产生查询,当第一个游标的第一个next方法被出发后默认先会查询100条或者4M大小的数据(选择两者这间的最小者)。当游标已经存在的数据已经耗尽,游标会再去忽的100条数据或者4M大小的数据。所以不必担心游标每次next都会去查询。
var cursor = db.product.find();
cursor.forEach(function(item){
print(item.product_name);
});
在之前我写过关于SQL反模式的文章,其中说过不要用MySQL的random查询,可以通过random得出一个值然后,通过这个值查询主键大于这个值的数据,limit为一条数据,这样我们就可以获得一条随机的数据了。同样的MongoDB也可以这样去做,不过MongoDB当中主键不是一个自动增长的数,所以之前MySQL中的随机查询我们就用不上了。
我们可以通过为文档添加相应的random属性:
var cursor = db.product.find();
cursor.forEach(function(item){
item.random = Math.random();
db.product.save(item);
});
db.product.find();
添加完之后,我们可以通过以下这种方式去获得随机的文档:
db.product.find({"random":{$lt:Math.random()}}).limit(1);
当然如果以上的查询查不到数据就可以通过$gt来进行查询,如果两个都查询不到任何数据就可以直接返回空了。
快照查询是一种安全的查询操作,MongoDB在文档修改后导致原位置无法扩展,会将文档移动到末尾然后进行修改扩展。所以以下这种情况就可能会出现问题
var cursor = db.product.find();
cursor.forEach(function(item){
item.keyword.push("New");
});
如果在添加新的关键字时,发现当前位置没有足够的空间存储新的关键字,MongoDB会将这个文档移动到末尾,然后添加新的关键字。但是这样会导致cursor会在末尾获得到同样的文档。基于解决这种问题,我们可以使用快照查询:
var cursor = db.product.find().snapshot();
cursor.forEach(function(item){
item.keyword.push("New");
});
使用snapshot之后会,按照_id索引去遍历执行。但是虽然这样会安全一点,但是事实上查询效率会有所降低。如非必要也不会使用快照查询。
其实在更新的文档当中我已经写过一些书库命令了,以下是一些补充:
通常我们会使用db.collection_name.drop()这种方式去删除一个collection
其中我们可以直接使用数据库命令:
db.runCommand({"drop":"product_pv"});
{
"ns" : "product_service.product_pv",
"nIndexesWas" : 1.0,
"ok" : 1.0
}
获得最后一次执行的结果:
db.runCommand({"getLastError":1});
返回结果如下:
{
"connectionId" : 10.0,
"n" : 0.0,
"syncMillis" : 0.0,
"writtenTo" : null,
"err" : null,
"ok" : 1.0
}
有些操作只能够是管理员执行,所以不能使用runCommand了,而是adminCommand。例如关闭MongoDB的服务:
db.adminCommand({"shutdown":1});