你知道的不知道的mongodb语法
2019-03-15 本文已影响12人
xurna
前言
最近在用mongodb数据库的时候,在运用在一些实际场景时,发现一时间没有关系型数据库这么习惯,官方的文档也显得很散乱不具体,为此我还去查询了很多相关资料,因此收获颇多,感觉是官方文档里面都没有仔细提及的知识点,因此作此文总结一番。
sql语句
假设有一个数据库集合结构为如下:
const BookSchema = new mongoose.Schema({
name: String,
author: String,
price: String,
chapter:{type:[Object],default:[]}
})
增
var Book = mongoose.model('Book', BookSchema);
const _book = new Book({
name: '老人与海',
author: '欧内斯特·海明威',
price: 30,
chapter:[
{"cname" : "老人与海","cnum":"一"},
{"cname" : "白象似的群山","cnum":"二"},
{"cname" : "大双心河(一)","cnum":"三"},
{"cname" : "大双心河(二)","cnum":"四"},
})
_book.save((err) => {});
删
删除符合条件的第一个文档:
Model.remove(conditions,callback);
Model.deleteOne(conditions,callback);
删除符合条件的所有文档:
Model.deleteMany(conditions,callback);
查
普通查询:
查询所有:
Model.find( conditions,[projection],[options],callback );
根据Id属性查询:
Model.findById( Id,[projection],[options],callback );
查询符合条件的第一个文档
Model.findOne( conditions,[projection],[options],callback );
联表查询:
待补充...
复杂查询:
Book
.find({ name: /libai/ })
.where('chapter.cname').equals('Ghost') // Book.chapter.cname是Ghost
.where('price').gt(20).lt(100) // 20 < Book.price <100
.where('author').in(['李白', '杜甫'])//author是李白或者杜甫
.limit(10) //限制10条记录
.sort('-price') //根据price的倒序排
.select('name price') //选择name和price字段
.exec(callback);
模糊匹配:
// or表示在数组里的条件满足一个即可,$regex表示一个正则表达式,匹配了key,同时,加入了$option的$i表示忽略大小写
Book.find({
$or: [
{'name': {'$regex': key, $options: '$i'}},
{'author': {'$regex': key, $options: '$i'}}]
})
.populate('Store', 'name')
.exec(function (err, books) {
if (err) {
callback(err);
} else {
callback(null, books);
}
})
改
- 使用
$set
修改器更新字段
// 更新某个字段,最常见
Book.update({name:'老人与海'},{ $set:{name:'挪威的森林'}})
- 使用数组修改器更新数组字段
$push
:在一条文档的对应的键数组中新增一个值,能新增重复的值,如果指定的键已经存在,它会向已有的数组末尾加入一个元素,要是没有就会创建一个新的数组。
// 如果新增两次,则会得到两个美女与野兽的字段
Book.update({name:'老人与海'},{ $push:{chapter: {"cname" : "美女与野兽","cnum":"一"}})
//结果变成:
{
name: '老人与海',
author: '欧内斯特·海明威',
price: 30,
chapter:[
{"cname" : "老人与海","cnum":"一"},
{"cname" : "白象似的群山","cnum":"二"},
{"cname" : "大双心河(一)","cnum":"三"},
{"cname" : "大双心河(二)","cnum":"四"},
{"cname" : "美女与野兽","cnum":"一"}
}
$pushAll
:用法和$push相似,可以批量添加数组数据,即可以添加整个数组
Book.update({name:'老人与海'},{ $pushAll:{chapter: {"cname" : "美女与野兽","cnum":"一"}, {"cname" : "老人与海","cnum":"一"}})
//结果变成:
{
name: '老人与海',
author: '欧内斯特·海明威',
price: 30,
chapter:[
{"cname" : "老人与海","cnum":"一"},
{"cname" : "白象似的群山","cnum":"二"},
{"cname" : "大双心河(一)","cnum":"三"},
{"cname" : "大双心河(二)","cnum":"四"},
{"cname" : "美女与野兽","cnum":"一"},
{"cname" : "老人与海","cnum":"一"},
}
$ne
:不重复插入数据。
// 如果已经有‘美女与野兽’这条数据,则不会再插入
Book.update({"chapter.cname":{$ne:"美女与野兽"}},{$set:{"cname":"美女与野兽","cnum":"一"}})
$addToSet
:自动判断数据是否存在,而且它和$each
结合使用,还能同时在数组中插入多个数据,这是ne没办法办到的。
Book.update(
{name:'老人与海'},
{$addToSet:{"chapter":{$each:[
{"cname" : "美女与野兽","cnum":"一"},
{"cname" : "美女与野兽2","cnum":"二"}
]}}})
$pop
:删除数组中的第一个恶或者最后一个。
// 删除chapter数组中的最后一个值
Book.update({name:'老人与海'},{ $pop:{chapter: 1})
//结果变成:
{
name: '老人与海',
author: '欧内斯特·海明威',
price: 30,
chapter:[
{"cname" : "老人与海","cnum":"一"},
{"cname" : "白象似的群山","cnum":"二"},
{"cname" : "大双心河(一)","cnum":"三"},
}
// 删除chapter数组中的第一个值
Book.update({name:'老人与海'},{ $pop:{chapter: -1})
$pull
:删除数组中匹配到的所有值
// 假设原来已经有两个‘大双心河(一)’的域,则删除会把2个都删除掉
Book.update({name:'老人与海'},{ $pull:{chapter: {"cname" : "大双心河(一)","cnum":"三"}})
//结果变成:
{
name: '老人与海',
author: '欧内斯特·海明威',
price: 30,
chapter:[
{"cname" : "老人与海","cnum":"一"},
{"cname" : "白象似的群山","cnum":"二"},
{"cname" : "大双心河(二)","cnum":"四"},
}
$pullAll
:一次性删除多个指定的数值
Book.update({name:'老人与海'},{ $pullAll:{chapter: {"cname" : "大双心河(一)","cnum":"三"},{"cname" : "大双心河(二)","cnum":"四"}})
//结果变成:
{
name: '老人与海',
author: '欧内斯特·海明威',
price: 30,
chapter:[
{"cname" : "老人与海","cnum":"一"},
{"cname" : "白象似的群山","cnum":"二"},
}
$unset
:删除指定的键值对。
Book.update({price:'3'},{ $unset:{price: 1 })
//结果变成:
{
name: '老人与海',
author: '欧内斯特·海明威',
chapter:[
{"cname" : "老人与海","cnum":"一"},
{"cname" : "白象似的群山","cnum":"二"},
{"cname" : "大双心河(一)","cnum":"三"},
{"cname" : "大双心河(二)","cnum":"四"},
}
$
:数组定位符 ,如果数组有多个数值我们只想对其中一部分进行操作我们就要用到定位器。
// 修改器名称:$
// 语法:{ $set: { array.$.field : value} }
// 我们要把‘cname’为‘老人与海’的文档修改‘cnum’为100
Book.update({chapter.cname:'老人与海'},{ $set:{chapter.$.cnum: ‘100’ })
//结果变成:
{
name: '老人与海',
author: '欧内斯特·海明威',
price: 30,
chapter:[
{"cname" : "老人与海","cnum":"100"},
{"cname" : "白象似的群山","cnum":"二"},
{"cname" : "大双心河(一)","cnum":"三"},
{"cname" : "大双心河(二)","cnum":"四"},
}
对于update方法,更建议用updateOne
或者updateMany
,例如:
// 把符合条件的文档更新多条数据
Book.updateMany({ name: { $in: ['xxx','xxx','xxx'] } }, { $push: { chapter: {"cname" : "xxx","cnum":"xxx"} } }, { multi: true })
优化
- 有时候会遇到这样的后台输出warnings:“DeprecationWarning: collection.update is deprecated. Use updateOne, updateMany”,其实是官方是想在未来版本中移除某些方法,而使用新的方法,所以建议我们用新方法,详情:
To fix all deprecation warnings, follow the below steps:
mongoose.set('useNewUrlParser', true);
mongoose.set('useFindAndModify', false);
mongoose.set('useCreateIndex', true);
Replace update() with updateOne(), updateMany(), or replaceOne()
Replace remove() with deleteOne() or deleteMany().
Replace count() with countDocuments(), unless you want to count how many documents are in the whole collection (no filter). In the latter case, use estimatedDocumentCount().
- 更多的条件操作符:
$or 或关系
$nor 或关系取反
$gt 大于
$gte 大于等于
$lt 小于
$lte 小于等于
$ne 不等于
$in 在多个值范围内
$nin 不在多个值范围内
$all 匹配数组中多个值
$regex 正则,用于模糊查询
$size 匹配数组大小
$maxDistance 范围查询,距离(基于LBS)
$mod 取模运算
$near 邻域查询,查询附近的位置(基于LBS)
$exists 字段是否存在
$elemMatch 匹配内数组内的元素
$within 范围查询(基于LBS)
$box 范围查询,矩形范围(基于LBS)
$center 范围醒询,圆形范围(基于LBS)
$centerSphere 范围查询,球形范围(基于LBS)
$slice 查询字段集合中的元素(比如从第几个之后,第N到第M个元素)
总结
总的来说,mongodb的nosql对于像mysql这种关系型数据库也是有优势的,数据结构更加随意,不涉及到表与表之间的关系。