一文带你了解Navicat中MongoDB查询的高级用法

Navicat 是一款非常流行的数据库管理软件,可以通过 GUI 界面进行数据库管理,也可以通过编写代码来操作数据库。

在使用 Navicat 进行 MongoDB 查询时,我们不仅可以使用 MongoDB 中的基础查询语句,还可以使用使用其内置的 JavaScript 引擎执行代码段,进行各种数据库操作。

JavaScript 引擎介绍

在 Navicat 查询界面中,可以编写复杂 JavaScript 函数操作数据库。经过使用测试,它的脚本功能有以下特点:

  1. 会将脚本中最后一条语句的返回值输出到结果界面

  2. 在查询窗口生命周期内,脚本中定义的变量会一直存在

    比如重复执行 let userId = 'myUserId' 时,会提示变量已经重复声明了:

    1
    2
    3
    4
    let userId = 'ganmx'
    > [Error] SyntaxError: redeclaration of let userId
    at line 1, column 1
    > 时间: 0.002s

查询入口

所有的查询都以内置的 db 对象开始,比如查找用户的语句为:

1
db.user.find()

集合引用

通过以下方式来获取集合对象:

  1. db.collectionName
  2. db.getCollection('collectionName')

集合函数

集合对象上的提供的函数有:

  • aggregate(pipeline,options)
  • bulkWrite(operations,options)
  • convertToCapped(maxBytes)
  • copyTo(newCollection)
  • count(query,options)
  • createIndex(keyPatterns,options)
  • dataSize()
  • deleteMany(filter,options)
  • deleteOne(filter,options)
  • distinct(field,query,options)
  • drop()
  • dropIndex(index)
  • dropIndexes()
  • ensureIndex(keys,options)
  • explain(verbosity)
  • find()
  • find(query,projection)
  • findAndModify(document)
  • findOne(query,projection)
  • findOneAndDeleted(filter,options)
  • findOneAndReplace(filter,replacement,options)
  • findOneAndUpdatae(filter,update,options)
  • getDB()
  • getMongo()
  • getIndexes()
  • getPlanCache()
  • getShardDistibution()
  • getShardVersion()
  • group(options)
  • help()
  • initializeOrderedBulkOp()
  • initializeUnorderedBulkOp()
  • insert(document,options)
  • insertMany(documents,options)
  • insertOne(document,options)
  • isCapped()
  • latencyStats(options)
  • mapReduce(map,reduce,options)
  • reIndex()
  • remove(query,options)
  • renameCollection(target,dropTarget)
  • replaceOne(filter,replacement,options)
  • save(document,options)
  • stats(scale|options)
  • storageSize()
  • totalIndexSize()
  • totalSize()
  • update(query,update,options)
  • updateMany(filter,update,options)
  • updateOne(filter,update,options)
  • validate(full)
  • watch(pipeline,options)

全局变量

MongoDB 的查询编辑器等同于浏览器的 console,因此 console 上暴露的方法与变量,在 MongoDB 中都可以使用,比如 Math、Date 等等。

findOne 返回值

findOne 返回的类型为:NAVBson,它表示文档值

find 返回值

与 finOne 不一样,find 的返回值是一个集合,返回值类型为:NAVCollectionChainInfo,里面每个元素的类型是 NAVBson

可以通过下标访问集合中的每个元素,如果要使用数组的方法,需要调用 .toArray() 后再进行操作

它提供以下函数:

  • addOptions(flag)
  • batchSize(size)
  • close()
  • collation(<collation documents>)
  • comment(comment)
  • count(applySkipLimit)
  • explain(verbose)
  • forEach(function)
  • hasNext()
  • help()
  • hint(index)
  • isClosed()
  • isExhausted()
  • itcount()
  • limit(<number>)
  • map(function)
  • max(indexBounds)
  • maxScan(maxScan)
  • matTimeMS(<time limit>)
  • min(indexBounds)
  • next()
  • noCursorTimeout()
  • objsLeftInBatch()
  • pretty()
  • readConcern(level)
  • readPref(mode,tagSet)
  • returnKey()
  • showRecordId()
  • size()
  • skip(offset)
  • snapshot()
  • sort(sort)
  • tailabel(awaitData)
  • toArray()

aggregate 返回值

aggregate 的返回值类型是:NAVCollectionCursor,它提供以下方法:

  • close()
  • forEach(function)
  • hasNext()
  • help()
  • isClosed()
  • isExhausted()
  • itcount()
  • map(function)
  • next()
  • objsLeftInBatch()
  • pretty()
  • toArray()

事务

在 Navicat 中,使用以下语句启用 MongoDB 事务

1
2
3
4
5
6
7
8
9
10
session = db.getMongo().startSession();
session.startTransaction();
try{
// custom code here

session.commitTransaction();
} catch(error) {
session.abortTransaction();
}
session.endSession();

函数示例

以下为删除用户示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
function deleteUsers()
{
const users = db.user.find({
status: 0
}).toArray()
session = db.getMongo().startSession();
session.startTransaction();
try{
// 删除关联的信息,比如 userExtra
db.user_extra.deleteMany({
userId: {
$in: users.map(x => x._id)
}
}, {
sesion
})
// 删除自己
db.user.deleteMany({
userId: {
$in: users.map(x => x._id)
}
}, {
sesion
})

session.commitTransaction();
} catch(error) {
session.abortTransaction();
}
session.endSession();
}

deleteUsers()

为什么需要将逻辑包裹在函数中呢?请看后文解析。

查询器生命周期

查询编辑器的生命周期等同于 tab 窗体的存续时间,而不是在每次执行【运行】后就会释放。因此,如果在编辑器根中定义了变量,下次再运行,会提示变量重复声明。

可以使用闭包来解决这个问题:

1
2
3
4
5
6
7
8
9
10
11
// 多次运行这段代码时,不会出现变量重复声明的异常
function handleInFunc() {
let userIdTemp = 'pingkl'
let users = db.user.find({
userId: userIdTemp
})
return {
userId: 'pingkl'
}
}
handleInFunc()

参考

本文参考以下文章,在此致以诚挚谢意!

Navicat MongoDB