Mongodb——文档数据库

mongodb是一个文档数据库。

mongo操作

多个修改操作,但每个修改携带的数据包较小,可操作考虑批量操作.bulkWrite()改善性能。

MongoCollection是线程安全的。

db.coll.find()(shell、java api)之后接.limit .skip .sort不论编码调用顺序如何,执行时都是.sort -> .skip -> .limit。
如果要定义limit, sort, skip的顺序,应该使用.aggregate管道流。

db.createCollection()在coll已存在情况下会出错(java api则抛异常),db.getCollection后接CRUD则会自动创建coll,仅仅db.getCollection(String)数据库不会自动创建。

skip()

不是O(1)时间,是O(n)时间,不建议使用。

cursor

batchSize:

insert

insertOne()若在唯一索引字段上有重复值时插入抛出异常。

query

查询一个字段的值
mongo-shell: find({},{'field':1,'_id':0}),指定返回字段field,_id字段默认返回,若不需要该字段故需显式关闭。

不等于查询$nefind({field:{$ne: val}})

区间查询 $gt, $gte, $lt, $lte

db.collection.find({"myNum":{$gt:5, $lt:20}})

查询数组中满足条件的元素且只返回匹配的元素
$elemMatch匹配元素、"<数组字段名>.$"返回仅匹配的元素

.find({'myArray': {$elemMatch: {$gt: 50}}}) //查询数组中元素大于50的元素
.projection({'myArray.$': 1})  //仅返回数组中匹配上的元素

查询文档数组字段中满足条件的最后一个元素:

mongo-shell pretty output(beautiful output) 配置

查询数组字段非空的文档
有以下数种方式,假设目标字段名为"array"。

  1. $elemMatch$ne:
db.Collection.find({array:{$elemMatch:{$ne:null}}})
  1. $where+js数组的.length
db.Collection.find({$where:"this.array.length>0"})
  1. $not$size
db.Collection.find({array: {$not: {$size: 0}}})
  1. $exists和'.'路径试图访问首元素
db.Collection.find({{'array.0': {$exists: 1}}})
  1. $exists$ne
db.Collection.find({ array: { $exists: true, $ne: [] } })
  1. $gt
db.Collection.find({ array: { $gt: [] } })

TODO
查询object类型字段的键数量

匹配object类型字段非空

update

db.coll.updateOne(filter, update[, options])
db.coll.updateMany(filter, update[, options])
db.coll.replaceOne(filter, update, options)

update时不能在同一字段上有多个operator。即不允许这样的update:
.update({},{$pull:{"entity":'a'}, $addToSet:{entities:'b'}})

.updateOne查找一个数组字段中某个元素更新时,参数提供 {\(set:{'arrayField.\)':newValue},将会替换原来的值,需注意的是,当元素是json时(提供的newValue新值也是json),操作会直接替换掉原来的json,不是在原文档上添加字段或修改字段值。

涉及数组字段中更新查询到的元素时,在提供了占位符'$'的更新时,不存在upsert:true,因为在

更新/删除字段:

findAndUpdate(query, {"\(set", {field1:'val1'...}, "\)unset": {"fieldx":"值无所谓"}})

尽管insert方法没返回值,但驱动会自动生成_id(如果没有提供),并put到被插入的Document中。_id会根据时间戳、主机等信息生成。

upsert(search, doc) -> update or insert,这里的search相当于where条件,这比在客户端先search是否存在,然后决定insert还是update高效。

键名(key)可以是任意Unicode字符,但不允许包含点号.和美元符$,可以通过转义的方式存,常见的转义方式是将这两个ascii字符转到Unicode:. -> '\u2024':[․],\uff0e':[.], $ -> '\ufe69':[﹩],'\uff04':[$]。

db.collection.distinct("field") <- select distinct field

update operators:

**\(pull** {\)pull: { : <value | condition> } } 从array字段删除符合条件的元素。

**\(pullAll** {\)pullAll: { : [ value1, val2, ...] }}
从array字段删除操作中提供的多个元素(不是匹配条件),值为数组,不能是单值。

**\(push** 插入(结合\)position)或追加(无\(position)元素到数组字段,如果追加多个元素(一次性插入多个)需结合\)each。

{\(push: {<field>:<value>}} {\)push: {field: {$each: [,] } }}}

**\(addToSet** {\)addToSet:{: },如果参数值是数组,则会被视为单一元素插入到目标字段(成为内嵌数组);如果想对一组元素都进行\(addToSet操作,应将这组元素封装到\)each操作:

{
    $addToSet: {
        "field":{$each:['v1','v2'...]}
    }
}

$set

$setOnInsert
set when insert in upsert mode

delete/remove doc

.deleteOne(filter)
.deleteMany(filter)

aggregate

.aggregate([pipe1, pipe2])

$match, $project

count object keys: 利用\(objectToArray将对象转为数组,然后利用\)size。
.aggregate({\(project: {out: {\)size: {\(objectToArray: "\)valueeOfSomeKey"}}}})

数组上的aggregate: \(size(aggregate) 例:获取值类型为数组的字段"entities"上数组的长度 .aggregate({\)project:{ asNewFieldName: {\(size: "\)entities"}}),注意,引用字段entities时需要字段名前加\(,否则被认为是string常量,导致\)size操作失败。

update: { "\(update-opterator": {}, "\)update-operator":{} }

对于.updateOne(filter, update, opts),当filter是eq(全匹配)且upsert为true时,如果update的文档不存在,则在插入时会自动把filter上的字段-值插入。例: getCollection.updateOne(Filters.eq("nerword", "xxxxxx"), new bson.Document("$addToSet", new bson.Document("entities", "zzz")),new UpdateOptions().upsert(true)),如果不存在该nerword的文档,则插入时会加入nerword,即有新文档{nerword:'xxxxxx', entities:['zzz']}。对于replaceOne with upsert: ture 在插入时不会添加filter的字段。

updatereplace在filter指定的文档不存在且upsert:false时无任何操作。

update operator:
\(rename \)set
$unset

backup/restore export(dump)/import

导出远程数据库集合

mongoexport -h <host> --port <port> -u <user> -p <pass> -d <db> -c <collection> -o <outputfile.json>

mongoimport -h .. --port .. -u .. -p .. -d .. -c .. --file <data.json>
# import csv
mongoimport -d <db> -c <coll> --type csv --headerline (first line is headerline, as fields) --ignoreBlanks (ignore blank values) --file <FILE>

数据库database

show dbs # 列举db  
use <db> # 切换到db,如果不存在则在需要时创建   
db # show current db  
#use之后内置变量db指向当前的database。  
use <db> # create <db>
db.dropDatabase() # drop database

用户user

db.getUsers()

db.createUser(
{
    user:'name'
    pwd:'password'
    roles:[{role:'what-role',db:'which-db'}]
})

db role

show roels
// create role

// drop role

//增加授权,不会先清除之前的授权
db.grantRolesToUser('username',[
{role:'role1',db:'db1'}, {role:'role2',db:'db2'}])
// 收回授权
db.revokeRolesFromUser('username',[{role:'role1',db:'db1'},{role:'role2',db:'db2'}])

index 索引

db.coll.createIndex(keys, options)

//如果不存在则创建
db.collection.createIndex(
    {<field>: 1/-1, <anotherField>: 1/-1}, 
    <optional>{unique: true, name:"name for index", sparse: true|false}
)

字段有重复时创建唯一索引(unique index)会失败,{unique:true, dropDups:true}在 MOngoDB 3.0后不可取,dropDups选项无效。

数据状态异常

查询集合中文档数量 db..count()(包括.stats())的结果和通过find()结果遍历次数不一致,这是因为mongodb关于此集合的数据状态有异常,需要执行db..invalidate(true)来矫正数据,参考mongodb问题 count() incorrect。数据有误时可考虑用db..count({_id:{$exists:true}})代替count()。

mongo java driver

结论一般针对3.4.2版本

类型为Array[?]的字段值不能被解码,要为Collection[?]才行。例如,String[] x,则new Document("key",x)时,x存储会识别,因无法找到[Ljava.lang.String的codec,而存储转为List的x(x.asList)则能成功。

insertMany之前先判断插入的集合是否为空,因为插入空集合会引发异常(╮(╯▽╰)╭)

mongo-java-drive 3+
collection.updateOne(Filter.eq("id-or-other-field","xxxxxx"), new Document("$set", Document.parse(json: {timstamps: new Date, xx:{...})

updateOne vs. findOneAndUpdate 后者会返回更新前的值,前者不会。

插入整数时一定注意区分是int还是long型,分别与mongodb的Int32、Int64对应,如果是后者,用java api Document.getInteger会出异常,而往往直接用该方法取整数型数据。

无需auth信息的serve不能new 带credential的MongoClient构造器(MongoClient(ServerAddress, List[MongoCredential])。

【添加codec】
MongoClientOptions.builder().codecRegistry(CodecRegistries.fromRegistries(CodecRegistries.fromCodecs(new LocalDateTimeCodec()), MongoClient.getDefaultCodecRegistry()))

new Document(Map<String,Object>)(如从一个json构建)并不会将深层Map<String,Object>转为Document,因此使得插入时转码失败(code错误)。从json到document的一种正确方式是Document.parse(String json)。

mongodb python driver

package dependency: pymongo

from pymongo import MongoClient
cursor = MongoClient(host,port)['db']['coll'].find({key:val, k2:val2}, projection=[(key:1),(key2:1)])
try:
    while True:
        cursor.next()
except StopIteration:
    # reach end of stream
finally:
    cursor.close()

mongodb scala driver

dependency: org.mongodb.scala:mongo-scala-driver_2.11 or _2.12

SHIT!!!!! HOLY SHIT !!!!!!!! also mongodb casbah !!!!! SHIT !!!!!!!! 2018.3.22

mongodb spark connector

org.mongodb.spark:mongo-spark-connector_2.11:2.2.1

val sc = new SparkContext(new SparkConf().setAppName("myapp")
  .set("spark.mongodb.input.uri", "mongodb://user:pass@host:port/db.collection"))

val rdd = MongoSpark.load(sc)

// 官网建议使用withPipeline(而非RDD.filter),不但能使数据在返回到rdd前过滤,还能在没有数据匹配时不引起异常,否则RDD.filter会导致NPE。
val aggregatedRdd = rdd.withPipeline(Seq(Document.parse("""{$match:{}""")))

如果不希望通过uri传入用户名密码认证信息,需要自定义MongoClientFactory,作为MongoConnector的构造参数,然后将MongoConnector作为MongoSpark.Builder的connector创建MongoSpark,之后调用toRdd获得MongoRDD。(注意这是版本spark-connector_2.11:2.2.1。

FAQ

  1. sort排序失败
    Sort operation used more than the maximum 33554432 bytes of RAM. Add an index, or specify a smaller limit。
    解决:在文档量过大时排序字段需建索引。

  2. org.mongodb:mongodb-driver-core:3.6.3与org.mongodb.spark:mongo-spark-connector_2.11:2.2.1存在兼容问题,可能导致NPE。

安装mongodb server、client

centos:

vim /etc/yum.repo.d/mongo.repo

填入内容:

name=MongoDB Repository
baseurl=http://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/3.0/x86_64/
gpgcheck=0
enabled=1

默认配置文件为/etc/mongod.conf,服务器绑定的网络接口配置在bindIp:上,默认为0.0.0.0,如果只想为本机服务,则配置为127.0.0.1,如果配置为局域网ip(如10.36.124.131)则只能在lan接口上服务,本机(127.0.0.1)没有服务,如果要在本机及lan接口上服务则用逗号连接两个ip,逗号后不得有空格(bindIp: 127.0.0.1,10.36.124.131)。

手动安装:
下载对系统版本的server安装包,

Windows系统下将mongodb安装为服务的命令:

mongod --config "C:\Program Files\MongoDB\Server\3.4\conf\mongo.conf" --serviceName MongoDB --install

其中mongo.conf由自己创建,window版无默认配置文件,配置文件中必须包含dbpath和logpath,dbpath文件夹需提前创建,否则mongod无法成功启动。

mongodb由MongoDB,Inc开发,公司曾用名“10gen”。

mongodb doc离线版下载,原提供pdf格式,现提供epub格式。

(待丰富)
posted @ 2019-02-27 10:37  二球悬铃木  阅读(649)  评论(0编辑  收藏  举报