首页之约有些文章不一定是为了上首页投稿程序员

你知道的不知道的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);
        }
      })

// 更新某个字段,最常见
Book.update({name:'老人与海'},{ $set:{name:'挪威的森林'}})
// 如果新增两次,则会得到两个美女与野兽的字段
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 })

优化

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这种关系型数据库也是有优势的,数据结构更加随意,不涉及到表与表之间的关系。

阅读资料

上一篇下一篇

猜你喜欢

热点阅读