mongodb的存储结构是灵活可变的,但是,并不意味着我们就肆意地使用不规则的文档结构。不规则的文档结构对于开发和后期的维护都是一个灾难。所以,还是要有一个约定的格式。

但是,由于前期设计的不周详和其他种种原因,数据库文档结构在开发过程的中修改总是难以避免的,应该尽量减少这种修改。但是,到了必须改的时候还是得改:

 {
"_id" : ObjectId("54a1f775e4b03dad3af55c3c"),
"myId" : "54a0b115e4b00712935204ba",
"name" : "action",
"key" : "m_0",
"index" : 0,
"createTime" : ISODate("2014-12-30T00:53:09.483Z"),
"subMs" : [
{
"_id" : null,
"rm" : {
"mt" : "TEXT",
"content" : "撒东西"
},
"name" : "地说道",
"key" : "menu_0_0",
"type" : "CLICK"
}
]
}
{
"_id" : ObjectId("54b87996e4b04b29b92a71b1"),
"myId" : "54b5e8cce4b045d4121f5d63",
"rm" : {
"msgType" : "URL",
"url" : "http://www.abc.com"
},
"name" : "usercenter",
"key" : "user-center",
"type" : "VIEW",
"index" : 0,
"createTime" : ISODate("2015-01-16T02:38:14.643Z")
}] }

有很多这样类型的文档。 这个文档中的subMs字段中内嵌有若干个文档。要做的事情就是把subMs中的若干个文档脱离出来成为一个独立的文档,并且使新拆出来的文档保留原父文档的id。

脚本如下:

 var mList = db.m.find();
var mLength = mList.length;
var mArray = new Array();
// 这一步比较关键,因为find 方法会返回一个游标,
// 如果不先关闭,或者将此游标用完,接下来在继续往
// mongodb中插入数据会导致该游标发生混乱。
// 所以此处未往mongodb中修改前先把游标用完。
while(mList.hasNext()) {
mArray.push(mList.next());
}
for(var i = 0; i < mLength; i ++) {
var mItem = mArray.pop();
var sMList = mItem.subMs;
mItem.subMs = new Array();
if(sMList == 0 || sMList.slength == 0) {
continue;
}
var sMLength = sMList.slength;
for(var j = 0; j < sMLength; j ++) {
var sMItem = sMList.pop();
sMItem.pid = mItem._id.str;
sMItem.index = j;
sMItem.subMs = new Array();
sMItem._id = undefined;
db.m.insert(sMItem);
}
db.m.save(mItem);
}

第一次写起来还是有点吃力,

第一,是由于js的非常不熟悉。翻了好几次w3school才看出了点东西。

第二,是对mongodb查询游标的理解。

着重说说,mongodb 的游标:

游标:在mongodb查询中,返回一个可迭代的对象,这个对象就叫做游标。这个对象保存着所有的查询结果集。

游标的行为:

1. 在mongo shell 中,游标默认显示前20个结果集,敲入 it 翻页。显示下一个 20个。

关闭mongodb 的游标:游标在mongodb中如果没有被迭代到最后,那么它在10分钟后自动关闭。或者是被迭代到最后。

修改mongodb游标的自动过期时间方法为:

var myCursor = db.m.find().addOption(DBQuery.Option.noTimeout);

// DBQuery 这个对象中也有挺多东西,有空翻来看看

由于游标在生存周期中不是隔离的,游标存活期间在对一个文档的写操作可能会时该文档的返回次数超过一次。当这个文档被改变之后,这就是我在写上面脚本的时候一开始缺少了先把游标用完,就对原文档修改,造成错误。

所以,我上面的写法存在问题,当数据量很大的时候,把游标中所有的东西加载到内存后会把内存撑爆的。。。

解决办法:使用游标快照: (P707)

mongodb的游标会对一个文档返回超过一次,在一些特殊的情况下,那么这个时候就可以使用快照方法 snapshot().

snapshot()贯穿在_id字段上的索引,保证查询返回的每个文档出现的_id值不超过一次。(遵循_id值)

快照方法不保证数据返回时会返回单一时刻。 也不保证对插入和删除操作的隔离。

警告:

1.不能再分片集合中使用快照方法

2.不能在快照方法的同时使用 sort方法或者hint()方法。

作为一个选择,如果在集合中存在有一个或多个字段是永远不会改变的,那么可以在该字段上创建唯一索引,来得到和使用库依照方法类似的集合。查询时使用hint方法强制查询时使用这个唯一索引。

第三,mongo shell, 有个好东西, 当敲一个命令的时候,不敲后边跟上的括号,就能显示该命令底下将会执行的js方法。

比如以下命令:

>  db.m.find   回车后会显示对应的方法。

另外,有个挺好用的mongodb客户端:robomongo 值得推荐。

以上参考了mongodb的官方文档。写的很给力的一个文档。非常值得一看,居家备用查询也挺好。

mongodb 修改数据结构的一个例子以及小梳理的更多相关文章

  1. Spark小课堂Week7 从Spark中一个例子看面向对象设计

    Spark小课堂Week7 从Spark中一个例子看面向对象设计 今天我们讨论了个问题,来设计一个Spark中的常用功能. 功能描述:数据源是一切处理的源头,这次要实现下加载数据源的方法load() ...

  2. 一个有趣的小例子,带你入门协程模块-asyncio

    一个有趣的小例子,带你入门协程模块-asyncio 上篇文章写了关于yield from的用法,简单的了解异步模式,[https://www.cnblogs.com/c-x-a/p/10106031. ...

  3. [python]python 遍历一个list 的小例子:

    [python]python 遍历一个list 的小例子: mlist=["aaa","bbb","ccc"]for ss in enume ...

  4. C# 关于委托和事件的妙文:通过一个例子详细介绍委托和事件的作用;Observer模式简介

    委托和事件在 .Net Framework中的应用非常广泛,然而,较好地理解委托和事件对很多接触C#时间不长的人来说并不容易.它们就像是一道槛儿,过了这个槛的人,觉得真是太容易了,而没有过去的人每次见 ...

  5. Erlang 程序引发共享内存 bug 的一个例子

    虽然 Erlang 的广告说得非常好,functional.share-nothing.消息传递,blah blah 的,好像用 Erlang 写并发程序就高枕无忧了,但是由于 Erlang 信奉高度 ...

  6. 【C语言探索之旅】 第一部分第八课:第一个C语言小游戏

    ​ 内容简介 1.课程大纲 2.第一部分第八课:第一个C语言小游戏 3.第一部分第九课预告: 函数 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答案.还会带大家用C语言编写 ...

  7. 6、GNU makefile工程管理学习的一个例子

    在之前我们已经学习了一个文件的编译过程,但是做过项目的都知道,一个工程中的源文件不计其数,其按类型.功能.模块会分别放在若干个目录中,而这些文件如何编译就需要有一个编译规则,虽然现在很多大型的项目都是 ...

  8. 一个例子理解Predicate、Consumer和Stream

    一个需求: 把年龄大于20的学生的信息打印出来. 面向对象编程 public class Student { private String name; private int age; private ...

  9. 一个例子看懂所有nodejs的官方网络demo

    今天看群里有人用AI技术写了个五子棋,正好用的socket.io,本身我自己很久没看nodejs了,再加上Tcp/IP的知识一直很弱,我就去官网看了下net.socket 发现之前以为懂的一个官方例子 ...

随机推荐

  1. webstrom配置node环境一张图片说明问题

  2. 最简的Dubbo例子部署

    dubbo 中包含下面4个核心组件: 生产者.消费者.注册中心.监控中心.   简单部署的模块关系 生产者.消费者 最简版本的Dubbo部署只运行Demo Provider和Demo Consumer ...

  3. 利用Jersey构建REST之入门实例

    一.依赖包 1.目录结构如下:

  4. Mysql中的count()与sum()区别

    首先创建个表说明问题 CREATE TABLE `result` ( `name` varchar(20) default NULL, `subject` varchar(20) default NU ...

  5. MFC学习 MFCActiveX控件

    例子包含 1. 重绘activex控件显示区域 在activex的ctrl类中ondraw中实现 2.添加修改activex控件属性(前景色, 背景色, 自定义属性),, 只要在类视图中展开libra ...

  6. Windows 2008下部署Exchange Server 2007

    对于很多政府及企业来说,微软的邮件服务器Exchange Server都是一个不错的通信和协作平台选择,尤其新版邮件服务器Exchange Server 2007 和OCS的组合,在微软UC平台上创下 ...

  7. Android开发-API指南-<uses-library>

    <uses-library> 英文原文:http://developer.android.com/guide/topics/manifest/uses-library-element.ht ...

  8. win7下Oracle 11的安装

    把下载的win32_11gR2_database_1of2.zip和win32_11gR2_database_2of2.zip解压到一个database文件夹下,运行安装文件   Oracle11的卸 ...

  9. 百度地图API的使用方法

    百度地图API 开始学习百度地图API最简单的方式是看一个简单的示例.以下代码创建了一个520x340大小的地图区域并以天安门作为地图的中心: 1. <html> 2. <head& ...

  10. ASP.NET知识集

    ASP.NET知识集 编辑删除转载2015-06-23 16:31:55 标签:it //删除指定行数据时,弹出询问对话框 ((LinkButton)(e.Row.Cell[7].Controls[0 ...