fred-ye / summary

my blog
43 stars 9 forks source link

[DataBase]MongoDB的基本操作 #39

Open fred-ye opened 9 years ago

fred-ye commented 9 years ago

MongoDB的基本操作

MongoDB的启动

进入mongodb安装文件的根目录,运行mongod --dbpath=, dbpath=是指定数据库的位置。其使用如下所示:

FreddeMacBook-Air:software fred$ cd mongodb
FreddeMacBook-Air:mongodb fred$ ls
GNU-AGPL-3.0        THIRD-PARTY-NOTICES data
README          bin
FreddeMacBook-Air:mongodb fred$ bin/mongod --dbpath=./data

至此,数据库启动成功。 在windows下对于--dbpath后接的路径最好加上引号,如:

I:\fred\mongodb>mongod --dbpath="I:/fred/mongodb/data"

当然也可以在启动的时候指定日志的输出,代码如下:

FreddeMacBook-Air:mongodb fred$ bin/mongod --dbpath=./data --logpath= /Users/fred/Documents/tech/software/mongodb/logs/mongodb.log

让mongodb在后台运行,加上-fork参数

bin/mongod --dbpath=../data --logpath=../logs/mongodb.log -fork

其实和Mysql有些类似,Mysql启动的时候也是先运行mysqld启动数据库,然后再运行mysql命令进行数据库的相关操作。Mongo数据库也是一样,运行mongod启动数据库后,接着再开一个命令行窗口,运行mongo命令来执行数据库的相关操作。

退出mongo输入exit或者直接Ctrl + C

数据库的基本操作

默认情况下,登录到mongodb中,自动连接到test数据库,如下:

FreddeMacBook-Air:bin fred$ ./mongo
MongoDB shell version: 2.6.5
connecting to: test
> show dbs;
admin  (empty)
local  0.078GB
test   0.453GB
> exit;

采用show dbs查看当前有多少个数据库, use db_name(如:amin)是切换数据库, show collections是查看当前数据库下有多少个collection. mongo中的collection类似于关系型数据库中的表。

数据库和Collection的创建

在MongoDB中,数据库和Collection都是隐式创建的。无需手动创建,要使用时自动创建。如下:

> show dbs;
admin  (empty)
local  0.078GB
test   0.453GB
> use aa
switched to db aa
> show dbs;
admin  (empty)
local  0.078GB
test   0.453GB
> aa.c1.insert({name:'admin',password:'password1'});
2014-12-28T22:32:53.749+0800 ReferenceError: aa is not defined
> use aa
switched to db aa
> db.c1.insert({name:'admin',password:'password1'});
WriteResult({ "nInserted" : 1 })
> show dbs;
aa     0.078GB
admin  (empty)
local  0.078GB
test   0.453GB
> show collections
c1
system.indexes
> 

最初我的数据库中只有admin,local,test三个数据库,但是当我执行了切换到数据库aa,并执行db.c1.insert({name:'admin',password:'password1'}后,再执行show dbs发现aa数据库已经创建好了,如果用show collections会发现collection c1也创建了。

MongoDB支持string, integer, boolean, double ,null, array object等基本数据类型,还有data, object id, binary data, regular expression, code

插入

采用insert方法,插入的内容是json串,如下:

db.c1.insert({name:"user1"});
db.c1.insert({name:"user1"});
for(i =1; i< 30; i++) {
    db.c1.insert({name:"user"+i});
}

更新

采用update方法,使用如下:

db.collection.update( criteria, objNew, upsert, multi )

update()函数接受以下四个参数:

  • criteria : update的查询条件,类似sql update查询内where后面的。
  • objNew : update的对象和一些更新的操作符(如$,$inc...)等,也可以理解为sql update查询内set后面的
  • upsert : 这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入。默认是false,代表如果记录不存在,也不新增。 multi : mongodb默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。 摘自这里.

常见的操作示例:db.c1.update({name:"user3"}, {$set:{name:"user300"}});将 name值为user3改为user300.注意:默认情况下,只会更新第一个符合条件的记录。若想更新行:db.c5.update({name:"user1",{$set:{name:"user111"}},0 ,1)

操作符 说明
{$inc: {field : value}} 为某个字段添加指定值
{$set : {field : value}} 为某个字段设置值,当field不存在时,添加字段。
{$unset : {field : value}} 删除给定的字段
{$push : {field : value}} 将值追加到field中。
{$pushAll : {field : value_array}} 将数组追加到field中
{$pop : {field : index}} 删除数组中第index元素,index从1开始
{$pull : {field : value}} 删除数组中符合条件的记录
{$pullAll : {field : value_array}} 和$pull类似,只是此时的value_array是一个数组,可以同时删除多个。
{$rename: {old_field_name : new_field_name}} 修改字段名

说明:

  1. 对于$push:要求field类型是一个数组,如果field已经存在,就把value追加给field, 如果filed原来不存在,就新增一个字段,并赋值。如果field存在,但不是一个数组,将报错。
    • db.c1.update({name:"user1",{$inc:{age:1}}})
    • db.c2.update({name:"user1"}, {$pull:{fruit: {$nin:['apple']}}});

      删除

删除采用remove方法。

  1. 删除所有记录 db.c3.remove({})
  2. 删除指定条件记录 db.c3.remove({name: "user1"})

    查询

  3. 查询某个collection中所有数据 db.c1.find()db.c1.find({})效果是一样的.
  4. 可以指定查询条件:db.c1.find({name:"user5"});
  5. 指定返回的列:db.c1.find({name:"user5", {name:1}),在默认情况下,会返回_id这一列,如果不想返回这一列,可以写成db.c1.find({name:"user5", {name:1, _id: 0})
  6. 查找时的条件限制。如

    用途 操作符
    大于(>) $gt (grater than)
    小于(<) $lt (lower than)
    小于等于(<=) $lte
    大于等于(>=) $gte
    不等于 $ne
    字段是否存在 $exists
    数据存在于 $in
    数据不存在于 $nin
    或者 $or
    全部包含 $all
    数组长度 $size
    • db.c1.find({age:{$lt:19}})
    • db.c1.find({age:{$lt:19, $gt:3}})指定区间
    • db.c1.find({age:{exists:1}})
    • db.c1.find({age:{$in:[1,3,5]}}) $in操作类似于传统关系型数据库中的in
    • db.c1.find({age:{$nin:[1,3,5]}})
    • db.c1.find({$or: [{name:"user1"},{name:"user2"}]});
    • $all操作类似于$in,但$all要全数组里面的值全部包含在记录中。如db.c1.find({a:{$all:[1,2,3]}})返回的记录中字段a中必须要包含[1,2,3]。
    • db.c1.find({a:{$size:4}}})字段a是一个数组,且该数组有4个元素。
  7. 数量统计 db.c1.find().count()
  8. 排序:db.c1.sort({age:1})按age的升序排列,db.c1.sort({age:-1})按age的降序排列。
  9. 分页
    1. db.c1.find().limit(4) 从0开始输出4个。
    2. db.c1.find().skip(5).limit(5)跳过前5个,再取5个,相当于mysql中的SELECT * FROM USER LIMIT 5,5.
    3. 一个综合一点的例子:db.c1.find().sort({age:-1}).skip(2).limit(5).count(1);注意当查询语句中有skip, limit时,默认情况下,count会忽略这些条件,因此此处必须要设置count(1),否则前面的条件会没有利用上。
  10. 正则表达式: MongoDB中同样支持正则表达式查询,写得少,先空着哦。
  11. 去重: disctinct, db.c1.distinct("name")查询不同的name.
  12. 游标的使用
var cur = db.c1.find();
cur.forEach(function(x){print(tojson(x))});
  1. 关于null的查询
> db.c2.insert({name:"user1", nickname:"big god"});
WriteResult({ "nInserted" : 1 })
> db.c2.insert({name:"user2", nickname: null});
WriteResult({ "nInserted" : 1 })
> db.c3.insert({name:"user3"});
WriteResult({ "nInserted" : 1 })

查询:

> db.c2.find({nickname: null});
{ "_id" : ObjectId("54a4de74458e722da12097e9"), "name" : "user2", "nickname" : null }
> db.c2.find({nickname:{$exists: false}});
> db.c2.find({nickname:{type:10}});
  1. $slice
    • db.c1.find({},{post:{$slice: 2}}); //得到前两条post
    • db.c1.find({},{post:{$slice: -2}}); //得到后两条post
    • db.c1.find({},{post:{$slice: [20, 10]}}); //从第20条开始,取10条。
> db.c1.find();
{ "_id" : ObjectId("54a4db30458e722da12097e5"), "name" : "user1", "post" : [ 1, 2 ] }
{ "_id" : ObjectId("54a4db41458e722da12097e6"), "name" : "user2", "post" : [ 3, 4, 5 ] }
{ "_id" : ObjectId("54a4db57458e722da12097e7"), "name" : "user3", "post" : [ 6, 7, 8 ] }
> db.c1.find({},{post:{$slice: 2}}); //得到前两条post.
{ "_id" : ObjectId("54a4db30458e722da12097e5"), "name" : "user1", "post" : [ 1, 2 ] }
{ "_id" : ObjectId("54a4db41458e722da12097e6"), "name" : "user2", "post" : [ 3, 4 ] }
{ "_id" : ObjectId("54a4db57458e722da12097e7"), "name" : "user3", "post" : [ 6, 7 ] }

索引

MongoDB中会对_id字段默认建立了索引。

> db.system.indexes.find();
{ "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "test.c1" }
{ "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "test.c2" }
{ "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "test.c3" }

MongoDB中有着固定大小的集合(普通集合是没有大小限制的,随着数据的增多会不断的增大),以LRU(Least Recently Used最近最少使用)规则和插入顺序进行age-out(老化移除)处理,自动维护集合中对象的插入顺序,在创建是要预指定大小,如果空间用完,新添加的对象将会取代集合中最旧的对象,永远保持最新的数据。

  1. 插入速度极快
  2. 按插入顺序的查询输出速度极快
  3. 能够在插入最新数据时,淘汰最早的数据。 可用来储存日专信息,缓存少量文档。

固定集合需要显式的创建使用·createCollection

db.createCollection("c2", {capped:true,size:10000,max:5});//大小是10000字节,最多5条。
db.c2.stats();
db.c2.insert({name:"user1"});
db.c2.insert({name:"user2"});
db.c2.insert({name:"user3"});
db.c2.insert({name:"user4"});
db.c2.insert({name:"user5"});
db.c2.insert({name:"user6"});

执行以上代码,会发现user1这条记录已经被移掉了。

将普通集合转为固定集合:db.runCommand({convertTocapped:"c1",size:1000,max:3});

性能优化

  1. 创建索引
  2. 限定返回结果条数
  3. 查询使用到的字段,不查询所有字段
  4. 使用固定集合
  5. 使用慢查询日志。db.c1.find({name:"user1"}).explain()

    用户的管理

mongo中是有一个超级管理员,还有某个数据库的管理员两种。超级管理员要放到admin表中。 在mongo中要添加 --auth 增加安全性,用户授权。

添加用户用addUser,为用户授权采用auth。对于addUser,如果用户名相同,则相当于是修改密码的操作。

> db.system.users.find();
> use admin
switched to db admin
> db.addUser("admin", "admin");
WARNING: The 'addUser' shell helper is DEPRECATED. Please use 'createUser' instead
Successfully added user: { "user" : "admin", "roles" : [ "root" ] }
> db.auth("admin","admin");
1
> db.system.users.find();
{ "_id" : "admin.admin", "user" : "admin", "db" : "admin", "credentials" : { "MONGODB-CR" : "7c67ef13bbd4cae106d959320af3f704" }, "roles" : [ { "role" : "root", "db" : "admin" } ] }
> db.system.users.remove({user:"admin"});//删除某个用户

对于某个database添加用户,可以采用

> use test
switched to db test
> db.addUser("admin", "admin", true);//true表示只读

PHP 操作MongoDB

连接mongodb (conn.php)

<?php
    $conn = new Mongo("mongodb://irunning:abc123_@127.0.0.1:27017/irunning");
    $db = $conn->irunning;

查询 (find.php)

<?php
    include "conn.php";
    $user = $db->user;
    $condiction = array();
    $rs = $user->find($condiction);
    foreach ($rs as $val) {
        $id = $val['_id'];
        $username = $val['name'];
        echo "<a href=user.php?id=$id>$username</a></br>";
    }
    $conn->close();

详细 (user.php)

<?php
    include "conn.php";
    $user = $db->user;
    $oid = new MongoId($_GET['id']);
    $arr = array("_id" => $oid);
    $rs = $user->find($arr);
    foreach ($rs as $val) {
        print_r($val);
    }
    $conn->close();

插入(insert.php)

<?php
    include "conn.php";
    $user = $db->user;
    $array = array("name"=>'leo', "password"=>"password1", "age"=>"30");
    if($user->insert($array)) {
        echo "<script>location = 'find.php'</script>";
    } else {
        echo "insert fail";
    }
    $conn->close();

更新(update.php)

<?php
    include "conn.php";
    $user = $db->user;
    $arr = array("name"=>"leo");
    $valueArr = array('$set'=>array("password"=>"abc123_", "age"=>3));
    $opts = array("upsert"=> 0 , "multiple"=>1);
    if ($user->update($arr, $valueArr, $opts)) {
        echo "<script>location = 'find.php'</script>";
    } else {
        echo "update fail"; 
    }
    $conn->close();

删除(delete.php)

<?php
    include "conn.php";
    $user = $db->user;
    $arr = array("name"=>"leo");
    if ($user->remove($arr)) {
        echo "<script>location = 'find.php'</script>";
    } else {
        echo "delete fail";
    }
    $conn->close();