在项目中MongoDB的Map-Reduce功能做了许多统计任务,在重构代码的时候修改了_id对象里面的属性字段名称,当用db.collection.update({$rename:{"_id.a":"_id.b"}})的时候提示mongodb $rename affecting _id not allowed错误消息。于是只能通过写bash shell脚本来进行处理,之前学习MongoDB Manual时候里面有提到服务器端Javascript的特性但一直没去详细了解,今天正好有这个需求就查了下资料。

自MongoDB 2.4以后的版本采用V8引擎执行所有Javascript代码,允许同时运行多个Javascript操作,在2.4版以前在执行Javascript的时候要求先获取锁,所以一次只能执行一个Javascript操作;MongoDB提供了对Javascript的完整支持,如在Node.js、MongoDB服务器端和mongo shell里面都提供非常好的支持。

MongoDB对下列服务器端操作支持执行Javascript代码:

1)mapReduce或者相对应的mongo shell方法db.collection.mapReduce();

2)eval命令或者相对应的mongo shell方法db.eval()

3)$where操作符

4)在服务器端通过mongo shell实例运行.js文件

下面重点说说$where操作符以及在服务器端运行.js文件:

$where操作符能够传递Javascript表达式字符串或者完整的Javascript函数到MongDB的查询系统。$where操作符为我们在做复杂查询时提供极大的灵活性,但是要求数据库对于Collection中的每条记录都执行一次$where提供的Javascript处理操作,所以会对查询性能有明显的影响。因此只有当我们不能用标准的MongoDB查询操作符完成查询操作时才推荐使用。

使用$where也应该注意以下几点:

1.使用$where操作不能够利用数据库索引。

2.不能在$where Javascript表达式或函数里面执行数据库写操作。

3.为了避免对整个Collection文档进行扫描并在每条记录上执行Javascript代码,应至少包含一个其他标准的查询操作符如($gt,$in)对结果集先进行必要的过滤减少性能损耗。

那么什么情况下必须使用$where操作符呢?

当我们有需要比较同一记录里面不同字段的关系如this.credits==this.debits时,这种查询操作标准操作符没有提供支持,所以必须通过$where来实现;再比如当有一个字段是一个数组时,当我们想要通过数组的大小来过滤查询时,标准操作符$size只能接受固定大小的值如{cards:{ $size:3}},不能实现 {cards:{$size:{$gt:3}}} 这种查询,然而通过$where可以轻松实现这个需求。

看下面的Example Code:

db.myCollection.find( { $where: "this.credits == this.debits" } );
db.myCollection.find( { $where: "obj.credits == obj.debits" } ); db.myCollection.find( { $where: function() { return (this.credits == this.debits) } } );
db.myCollection.find( { $where: function() { return obj.credits == obj.debits; } } );
db.myCollection.find( { $where: function() { return this.cards.length>3; } } );

注意:这里this或者obj对象代表的是当前正在操作的记录。

另外如果查询仅仅由$where组成,这可以直接采用下面的用法:

db.myCollection.find( "this.credits == this.debits || this.credits > this.debits" );

db.myCollection.find( function() { return (this.credits == this.debits || this.credits > this.debits ) } );

标准的查询操作符和$where一起使用:

db.myCollection.find( { active: true, $where: "this.credits - this.debits < 0" } );
db.myCollection.find( { active: true, $where: function() { return obj.credits - obj.debits < 0; } } );

注意:为了改善查询性能MongoDB在$where执行前先执行所有其他非$where过滤条件来过滤结果集。在MongoDB 2.4及以后的版本的map-reduce、group和$where里面禁止访问某些全局变量,如db等。

 在Javascript文件里面写mongo shell脚本:

我们能够在Javascript文件里面写mongo shell脚本来操纵在MongoDB里面的数据或执行管理操作。

从mongo shell或者Javascript文件里面实例化数据库连接:

conn = new Mongo("[host][:port]");
db = conn.getDB("myDatabase");
//or
db = connect("localhost:27020/myDatabase");

同时MongoDB在Javascript里面提供了和在mongo shell里面的命令相对应的:如在mongo shell里面的show dbs,show databases,在Javascript里面可以通过db.adminCommand("listDatabases");获得同样的效果,又如在Javascript文件里面可以通过db=db.getSiblingDB("dbName");代替use dbName操作等等,详细列表查看:http://docs.mongodb.org/manual/tutorial/write-scripts-for-the-mongo-shell/

执行服务器端Javascript的几种方式:

1.在mongo shell里面通过load("myjstest.js")加载Javascript文件,然后在后面的命令里面可以调用该文件里面定义的函数了,就像普通的Javascript代码一样。在该js文件里面可以访问此次mongo shell会话里面的全局变量,如db等。

Example Code:

function rename_id_field(taskId,mrId){
print("taskId is "+taskId+",mapReduceId is "+mrId);
var collectionName = "test_collection";
var backupName = "test_collection_bak"
var count = db[collectionName].count({"value.taskId":taskId,"value.mapReduceId":mrId});
print("record size:"+count);
var pageSize=10000;
var pages = (count-1)/pageSize+1;
for(var p=1;p<=pages;p++){
var start = (p-1)*pageSize;
print("Page:"+p+",start record:"+start);
var cursor = db[cName].find({"value.taskId":taskId,"value.mapReduceId":mrId}).skip(start).limit(pageSize);
while(cursor.hasNext()){
var rd = cursor.next();
rd._id.key=rd._id.name1;
rd._id.tid=rd.value.taskId;
delete rd._id.name1;delete rd.value.taskId;
db[backupName].save(rd);
}
} }

将该文件保存在/opt/script/test.js,然后通过Linux命令行或者bash shell脚本的方式登陆到mongo shell,然后如下图所示:

2.在mongo shell里面使用文本编辑器编辑Javascript代码,首先需要在Linux系统里面指定环境变量如EDITOR=vim,然后如下所示:

MongoDB shell version: 2.2.0
> function f() {}
> edit f
function f() {
print("this really works");
}
> f()
this really works

3.通过db.eval()方式在mongo shell里面执行Javascript代码,如下所示:

db.eval( function(name, incAmount) {
var doc = db.myCollection.findOne( { name : name } ); doc = doc || { name : name , num : 0 , total : 0 , avg : 0 }; doc.num++;
doc.total += incAmount;
doc.avg = doc.total / doc.num; db.myCollection.save( doc );
return doc;
},
"eliot", 5 );

通过MongoDB提供的这几种Javascript服务器端支持方式足以满足我们对MongoDB数据库进行复杂日常运行维护的管理工作。

MongoDB对Javascript的支持的更多相关文章

  1. javascript里面支持el表达式和<s:iterator>

    javascript不支持jstl标签,支持<s:iterator>和el表达式

  2. JavaScript语法支持严格模式:"use strict"

    如果给JavaScript代码标志为“严格模式”,则其中运行的所有代码都必然是严格模式下的.其一:如果在语法检测时发现语法问题,则整个代码块失效,并导致一个语法异常.其二:如果在运行期出现了违反严格模 ...

  3. JSON 的正确用法:Python、MongoDB、JavaScript与AjaxJSON 的正确用法:Python、MongoDB、JavaScript与Ajax

    本文主要总结网站编写以来在传递 JSON 数据方面遇到的一些问题以及目前采用的解决方案.网站数据库采用 MongoDB,后端是 Python,前端采用“半分离”形式的 Riot.js,所谓半分离,是说 ...

  4. mongodb Sort排序能够支持的最大内存限制为32M Plan executor error during find: FAILURE

    1.一个比较老的游戏服维护,关服维护后启动时报错 2.看到关于mongodb的报错,于是去查一下mongodb的日志 Plan executor error during find: FAILURE, ...

  5. DBSync新增对MongoDB、ES的支持

    数据库同步工具DBSync近日进行了升级,最新版本为V1.9,新增了对MongoDB.Elasticseach(ES)的支持,具体情况:1.支持同型库之间的同步,如:MongoDB至MongoDB,E ...

  6. mongodb 压缩——3.0+支持zlib和snappy

    转自:https://scalegrid.io/blog/enabling-data-compression-in-mongodb-3-0/ MongoDB 3.0 with the wired ti ...

  7. CentOS6.8部署MongoDB集群及支持auth认证

    三个节点的副本集如下图所示: 实验目的: 配置MongoDB的3节点副本集 3个节点的副本集都要开启auth认证,并且开启认证后,能互相通信 第一步 - 准备环境 准备三个虚拟机,其中一个用作Prim ...

  8. Fundebug:JavaScript插件支持错误采样

    Fundebug的付费套餐主要是根据错误事件数制定的,这是因为每一个发送到我们服务器的事件,都会消耗一定的CPU.内存.磁盘以及带宽资源,尤其当错误事件数非常大时,会对我们的计算资源造成很大压力. 如 ...

  9. c# MongoDB分页辅助类,支持多条件查询

    创建一个获取MongoDB数据库实例的类 public class Db { private static IMongoDatabase db = null; private static reado ...

随机推荐

  1. 解决Ubuntu下在firefox中打开Microsoft Outlook Web Access中文乱码

    Edit---Preference--Content--Languages--Choose...---Select a langue to add... 添加中文

  2. [转]CentOS 6和CentOS 7防火墙的关闭

      CentOS6.5查看防火墙的状态: 1 [linuxidc@localhost ~]$service iptable status 显示结果: 1 2 3 4 5 [linuxidc@local ...

  3. 为iOS设计:图形和性能

    在之前的文章里,我们探讨了基于多种不同技术来实现自定义的UIButton,当然不同的技术所涉及到的代码复杂度和难度也不一样.但是我也有意提到了基于不同方法的实现所体现出的性能表现也不一一相同. [在屏 ...

  4. CentOS7安装OpenStack(Rocky版)-05.安装一个nova计算节点实例

    上一篇文章分享了控制节点的nova计算服务的安装方法,在实际生产环境中,计算节点通常会安装一些单独的节点提供服务,本文分享单独的nova计算节点的安装方法 ----------------  完美的分 ...

  5. [LeetCode&Python] Problem 821. Shortest Distance to a Character

    Given a string S and a character C, return an array of integers representing the shortest distance f ...

  6. Http常见状态码说明

    一些常见的状态码为: 200 - 服务器成功返回网页404 - 请求的网页不存在503 - 服务不可用 详细分解: 1xx(临时响应) 表示临时响应并需要请求者继续执行操作的状态代码.代码 说明100 ...

  7. page 分页

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...

  8. gtx860M,cuda9路1080p多高斯运动检测测试

    多高斯背景差分,非常吃cpu,特别是多路视屏,所以想用gpu做检测 后面的跟踪一系列的规则判断用cpu opencv+cuda+stl做了个测试 代码: // MTTestCudaMog.cpp : ...

  9. 转-java编译时error: illegal character '\ufeff' 的解决办法-https://blog.csdn.net/t518vs20s/article/details/80833061

    原文链接:https://blog.csdn.net/shixing_11/article/details/6976900 最近开发人员通过SVN提交了xxx.java文件,因发布时该包有问题需要回退 ...

  10. Nginx基础学习

    参考博客: http://www.2cto.com/os/201212/176520.html http://os.51cto.com/art/201111/304611.htm http://www ...