以下集合全部是用user,task集合,Mongodb的文档相当于MYSQL的行记录。有一些关键字加上了双引号是因为我在python中使用的大多数的$开头的关键字在mongodb查询里是不需要添加双引号的。
1,增
MongoDB 使用 insert() 或 save() 方法向集合中插入文档。
3.2 版本之后新增了 db.collection.insertOne() 和 db.collection.insertMany()。
1,save():如果 _id 主键存在则更新数据,如果不存在就插入数据。该方法新版本中已废弃,可以使用 db.collection.insertOne()
或 db.collection.replaceOne() 来代替。
2,insert(): 若插入的数据主键已经存在,则会抛出主键重复异常
db.user.save({key:value})
db.user.insert({key:value})
db.user.insertOne({key:value})
db.user.insertMany([{key:value},{key:val}])
2,查($xx:操作符)
MongoDB 使用 find(),findOne()方法向集合中查找文档,findOne()方法只会返回一个文档。
如果你需要以易读的方式来读取数据,可以使用 pretty() 方法,语法格式如下:
db.user.find({},{key:0,key:1}).pretty() #find(筛选条件,某列是否查询(0-不查询,1-查询),默认全部查询)
· 等于-走索引: db.user.find({key:value}).pretty()
· 小于-尝试使用索引: db.user.find({key:{$lt:value}}).pretty()
对于数值型索引,$lt 可以使用索引来优化查询,因为索引中存储的值都是有序的,可以快速定位到小于该值的文档。
对于字符串型索引,$lt 也是可以使用索引来优化查询,因为字符串也是有序的。
对于数组字段索引,$lt 查询会返回结果,但是不能使用索引加速查询。
总之,$lt 查询可以使用索引来优化查询,对于数值型和字符串型索引是可以的,对于数组字段索引,虽然可以查询出结果,但是无法使用
索引加速查询。
· 小于等于-索引与小于一样: db.user.find({key:{$lte:value}}).pretty()
· 大于-索引与小于一样: db.user.find({key:{$gt:value}}).pretty()
· 大于等于-索引与小于一样: db.user.find({key:{$gte:value}}).pretty()
· 不等于-会尝试使用索引来优化查询:
$ne 查询会对索引产生负面影响,因为它需要返回所有不等于该值的文档,而不仅仅是索引中有的文档。这意味着在查询中使用 $ne
可能会导致全集合扫描,这样会导致性能问题。
在使用 $ne 查询时,应该尽量避免使用索引字段,而应该使用其他字段来进行查询,这样可以避免全集合扫描。
例:
db.user.find({key:{$ne:value}}).pretty()
· 模糊查询(正则)-不走索引: db.user.find({key:{$regex:/value/}}).pretty()
· 查询是否存在某个字段--不走索引(1或者true都行:db.user.find({key:{$exists:1}}).pretty()
· in-数组大小过大,这可能会导致索引失效: db.user.find({key:{$in:[v1,v2]}}).pretty()
· not in-数组大小过大,这可能会导致索引失效 : db.user.find({key:{$nin:[v1,v2]}}).pretty()
· And-需要创建复合索引:db.collection.find( { $and: [ { field1: value1 }, { field2: value2 }, { field3: value3 } ] } )
创建复合索引:db.collection.createIndex( { field1: 1, field2: 1, field3: 1 } )
遵循类似于 MySQL 的最左前缀原则:
在使用复合索引时,MongoDB 会尝试使用索引的第一个字段来进行匹配,如果匹配成功,则使用第二个字段进行匹配,以此类推。
如果在某一步匹配失败,则整个查询将会失败。
这也是为什么需要按照索引字段的顺序来排列条件,因为MongoDB会按照索引字段的顺序来进行匹配。
在使用复合索引时,通常建议将经常使用的字段放在索引的最左边,这样可以更好的利用索引来加速查询。
· OR-不走索引: db.user.find({$or:[{key1:value1},{key2: value2}]}).pretty()
· Not-不走索引: db.user.find({key:{$not:{$eq:value}}}).pretty()
· NotOr-尝试使用索引: db.user.find({$nor:[{name:'小博'},{name:'测试小博'}]}) 比如查询name不为“小博”或者“测试小博”的数据。
使用 $nor 查询时,索引并不能有效优化查询性能。因为 $nor 查询需要返回所有不匹配任意条件的文档,而不是索引中有的文档,
这样会导致全集合扫描,对性能产生负面影响。所以在使用 $nor 查询时,应该尽量避免使用索引字段,改为使用其他字段来进行查询。
联合使用:db.user.find({key1:value1,key2:value2},{$or:[{key1:value1},{key2: value2}]}).pretty()
where k1 = v1 and (k2 = v2 or k3 = v3)
· 分页:db.user.find().pretty().limit(number).Skip(number) limit()条数,skip()跳过多少条
· 排序:db.user.find().pretty().sort({KEY:1}) 1 升序, -1 降序
· $size-需要在数组字段上使用数组索引才会走索引:用于查询数组字段中元素的数量。
有两种方式可以创建数组索引:
1.创建普通索引:可以在数组字段上创建普通索引,这样就可以支持对整个数组的查询。
db.collection.createIndex( { arrayField: 1 } )
2.创建多元索引:可以在数组字段和数组元素的字段上创建索引,这样就可以支持对数组元素的查询。
db.collection.createIndex( { arrayField.elementField: 1 } )
需要注意的是,如果数组元素是文档类型,需要使用"."来分隔文档字段和数组元素字段:
db.collection.createIndex( { "arrayField.elementField.subField" : 1 } )
需要注意的是,如果你想要查询的是数组中的一个特定的元素的话,需要使用 $elemMatch 操作符来查询,而不能直接使用索引来查询,
这样会导致扫描整个集合。
db.collection.find( { arrayField: { $elemMatch: { elementField: value } } } )
这样就可以利用索引加速数组元素的查询了。
例:
db.collection.find( { tags: { $size: 3 } } ) #查询所有tags字段数组长度为3的文档
· $type-不走索引:查询字段的数据类型
MongoDB 使用以下数字编码来表示不同的数据类型:
1:double
2: string
3: object
4: array
5: binary data
6: undefined
7: object id
8: boolean
9: date
10: null
11: regular expression
16: int32
18: int64
例:
db.collection.find( { age: { $type: 1 } } ) #查询所有age字段类型为double的文档
· $text -需要创建文本索引:用于在文本数据上执行全文搜索。
创建全文索引:db.collection.createIndex({field: "text"}, { default_language: "none" })
例:
db.collection.find( { $text: { $search: "text search", $language: "fr" } } )
MongoDB 会在所有已经建立文本索引的字段中查询 "text search"。
$language:是需要搜索的语言,默认英语,不支持中文全文搜索,以下是两种解决方法:
1.要使用第三方中文分词库或者使用第三方工具,比如 Elasticsearch 来支持中文全文搜索
2.MongoDB 5.5 及以上版本提供了新的语言类型 "none",但它只能用于跳过语言分析,直接搜索原始的文本,这样中文就可以支持
全文搜索了。
db.collection.createIndex({field: "text"}, { default_language: "none" })
· $where-不走索引: 是 MongoDB 中的一个特殊查询操作符,可以在查询中使用 JavaScript 表达式。
它允许在查询中使用更复杂的逻辑和运算符。
例:
db.collection.find(
{ $where: "this.fieldName > 10" }
)
使用 $where 查询时, MongoDB 将每个文档传递给 JavaScript 引擎,并对其进行评估。如果评估结果为 true,则文档将包含在结果中。
由于 $where 使用 JavaScript 表达式进行查询,因此它的性能通常比其他查询操作符要差。还需要注意的是,使用 $where 时,
不能使用索引,因此会导致性能问题。
聚合操作:在使用聚合操作符时如$group,$match,$sort,$skip,$limit等,如果在聚合操作符后面不是使用$sort操作符,
那么索引将不会被使用。
连表查询例子:
db.table_name.aggregate([
{
"$lookup": {
"from": "task_collection", #需要联合查询的另一张表B
"localField": "task_id", #表A的字段
"foreignField": "task_id", #表B的字段
"as": "task_docs" #别名
},
},
{
"$unwind":{
"path":"$task",
"preserveNullAndEmptyArrays":True #不加这参数的话,副表没记录的话会丢弃该数据(左连接)
} #拆分,将某个列表字段拆分成多行(连表查询时,返回的是数组,使用这个就可以转化为字典,前提你得保证是唯一的)
}
{
"$match": #筛选条件
{
"user_id": "name" #这里是根据表A中 user_id == name
}
},
{
"$addFields": { #与project异同,可以自定义字段
"task_id": "$task_docs._id", #如果是表字段需要加$
"自定义字段名":"自定义字段值",
}
},
{
"$project": #最终需要显示哪些字段,1:显示
{
"task_docs.task_id": 1,
"task_docs.task_name": 1,
"task_docs.task_type": 1,
"task_docs.evidence_content": 1,
"case_id": 1,
"task_id": 1,
"user_id": 1,
"_id": 0,
"task_name": {
"$ifNull": ["$task_name", "N/A"]
}, #设置默认值 ,仅限$project里使用
"endDate": { #例如判断日期是否有值,有值的话就格式化,否则就默认为空字符串
"$cond": [{
"$eq": ["$endDate", None]
}, "", {
"$dateToString": {
"format": "%Y-%m-%d %H:%M:%S",
"date": "$endDate"
}
}]
},
#类似枚举功能如果 status 字段的值为 1,则会返回数组的第二个元素 "未开始";如果值为 2,则会返回数组的第三个
'status': {
'$arrayElemAt': [["未知", "未开始", "进行中", "失败", "完成"], "$status"]
},
}
},
{
#排序
"$sort": {age: 1, name: -1}
},
{
"$skip": 2, #偏移
},
{
"$limit": 2, #条数
},
{ #自定义查询结果数据结构
"$facet": {
"data": [{
"$match": {}
}, {
"$limit": 10
}],
"total": [{
"$count": "total"
}]
}
},
])
#连表分页并获取总页数
db.collection.aggregate([
{
'$lookup': {
'from': 'product',
'localField': 'product',
'foreignField': '_id',
'as': 'product_info'
}
},
{
'$unwind': {
'path': '$product_info',
'preserveNullAndEmptyArrays': True
}
},
{
'$lookup': {
'from': 'newPatientInfo',
'localField': '_id',
'foreignField': 'taskid',
'as': 'new_patient'
}
},
{
'$unwind': {
'path': '$new_patient',
'preserveNullAndEmptyArrays': True
}
},
{
'$match': {}
},
{
'$addFields': {
'productname': '$product_info.productname',
'period': '$product_info.period',
'patientname': '$new_patient.patientname',
}
},
{
'$sort': {
'checkDate': -1
}
},
{
'$facet': {
'total': [{
'$count': 'total'
}],
'data': [{
'$skip': 0
}, {
'$limit': 10
}]
}
}
],allowDiskUse=True)
# 查看语句执行计划,查看该语句的性能,等价于mysql的:EXPLAIN SELECT * FROM table_name WHERE condition;
db.task.aggregate([{},{}],{ explain: true })
#用于指示查询是否允许使用磁盘空间来存储中间结果。默认情况下,MongoDB 查询操作的内存限制是 100MB,
如果查询的结果集或中间结果超过这个限制,将会抛出错误。通过设置 allowDiskUse=True,你可以允许查询使用磁盘空间来存储超出内存限制的结果。当查询的结果集或中间结果比较大时,使用 allowDiskUse=True 可以避免内存限制导致的查询失败。
它允许 MongoDB 将数据存储在磁盘上的临时文件中,以便能够处理更大规模的查询。
db.task.aggregate([{},{}],{ allowDiskUse: true })
3,改
MongoDB 使用 update() 和 save() 方法来更新集合中的文档。
update()方法第一个参数是放筛选条件的,用法和上面的查一样。可以用and和or或者联合一起用,第二个参数就是需要修改的键值。
修改第一条:db.user.update({k1:v1},{$set:{k2:v2}})
修改全部 : db.user.update({k1:v1},{$set:{k2:v2}},{multi:true})
save() 方法通过传入的文档来替换已有文档,_id 主键存在就更新,不存在就插入。
db.col.save({k1:v1,k2v2})
4,删
MongoDB remove() 函数是用来删除集合中的数据。
db.collection.remove(
<query>,
<justOne>
)
如果你的 MongoDB 是 2.6 版本以后的,语法格式如下:
db.collection.remove(
<query>,
{
justOne: <boolean>,
writeConcern: <document>
}
)
1,query :(可选)删除的文档的条件。
2,justOne : (可选)如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。
3,writeConcern :(可选)抛出异常的级别。
db.user.remove({k1:v1})
这个筛选条件同样和上面的一样,注意:如果是为空的条件,则就是删除全部,要小心!