关于Mongodb的问题:现在我要实现“上一篇”和“下一篇”浏览功能,在固定的查询条件和排序基础上,我想只传递ObjectId就可以查询到它的上一个文档和下一个文档,因为ObjectId不是数字ID,不可以像sql(用TOP和MAX/MIN)那样去查询,所以我现在是遍历了MongoCursor来确定它的上一个和下一个文档,但这样的方法不可取,很想找知道怎样实现才比较好?

2011-01-07 05:00:46

5 Answers

建议赶紧建立索引吧,要不你会悲剧的,objectId位数字对查询也是不利的,MongoDB 索引与关系数据库中的索引十分类似。您可以基于任何属性建树索引。此外,索引后的字段可所以任何数据类型,包含一个对象或数组。与 RDBMS 索引类似,可以应用多个属性创建复合索引,也可创建独一索引,确保不存在反复的值。

比如:

db.alphabet.ensureIndex({code: 1});
db.alphabet.ensureIndex({char: 1});
可以应用 dropIndex 和 dropIndexes 函数删除索引,这样你排序什么的就方便了
比如你的数据为:
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8c"), "code" : 97 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8d"), "code" : 98 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8e"), "code" : 99 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8f"), "code" : 100 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec90"), "code" : 101 }

code为索引
要获得下一97的吓一条,应用以下号令: > db.alphabet.find({code:98});
要获得下一97的上一条,应用以下号令: > db.alphabet.find({code:96});
详细你可以参考MongoDB 的手册,希望对你有帮助

下面那位仁兄说的有道理,其实这个建立了索引,查询上一条和下一条就很方便了

2011-01-07 07:16:08

这个问题我查了国内和国外的一些资料,也没有找到什么好的实现方法,由于你的ObjectId不是数字ID,也就是无规则的ID,所以只能通过MongoCursor来遍历定位它的前后文档。国外的人也是这么实现的。不过我感觉这种方式的应用应该不是很多吧。

2011-01-07 08:38:20

由于mongodb没有关系型数据库那样的自增键,虽然有个ObjectId,但它的生成机制有点特殊,所以一般不会直接用它进行数学计算,但还是可以用的,试试:

db.xxx.find({_id: {$lt: ObjectId('xxxxxxxxoooooo')}}).limit(1)
db.xxx.find({_id: {$gt: ObjectId('xxxxxxxxoooooo')}}).limit(1)

这个能用,就是有点bt,如果你只在一个mongodb实例(或者客户端)的情况下,具体原因参考各客户端的ObjectId生成机制。

还想到一个办法,如果你这个上下文的需求很强烈,可以给每一个文档额外添加一个键(比如叫context),其值为一个内嵌文档包含2个属性:

context:{previous: ObjectId('上一篇的文章id'), next: ObjectId('下一篇的文章id')}
,在发布内容的时候插入相关的值,虽然写入时麻烦点,但查询时会轻松很多,毕竟是读多写少嘛。
2011-01-07 10:40:34

不知道你objectId是怎么生成的,试试下面这种方法看行嘛:

//nest record: db.posts.find({_id: {$gt: curObjectId}}).sort({_id: 1 }).limit(1); //previous record: db.posts.find({_id: {$lt: curObjectId}}).sort({_id: -1 }).limit(1)
2011-01-07 11:17:21

一个数据库文件中,同一个namespace的extent可以有多个,每一个extent都有一些记录(record)组成,如果访问record,可以使用diskloc加上文件偏移(getOfs:位于diskloc中)获取。
同时每个extent中包括还包括两个重要属性:

DiskLoc xnext, xprev; /* next/prev extent for this namespace / 它们分别记录了同一namespace下,在extent链表中,当前extent的前或后一个extent的位置信息,上面 AdvanceStrategy中的next方法即实现了在两种遍历方向(上面已提到)上,在extent链接中跳转的方式,比如在forward方向: inline DiskLoc Record::getNext( const DiskLoc & myLoc) { // 如果当前 Record的nextOfs偏移不为空,表示在当前extent中还有后续记录可访问 if ( nextOfs != DiskLoc::NullOfs ) { / defensive */ if ( nextOfs >= 0 && nextOfs < 10 ) { // 是否为已删除的记录 sayDbContext( " Assertion failure - Record::getNext() referencing a deleted record? " ); return DiskLoc(); } return DiskLoc(myLoc.a(), nextOfs); // 获取下一条记录 } Extent * e = myExtent(myLoc); // 获取当前记录所属的Extent while ( 1 ) { if ( e -> xnext.isNull() ) return DiskLoc(); // 已到表尾. e = e -> xnext.ext(); // 跳转到下一个extent(以便进行next遍历) if ( ! e -> firstRecord.isNull() ) break ; // entire extent could be empty, keep looking } return e -> firstRecord; // 获取下一个extent中的第一条记录 }

2011-01-07 13:47:17
您不能回答该问题或者回答已经关闭!

相关文章推荐

  • C#中using指令的几种用法

    using + 命名空间名字,这样可以在程序中直接用命令空间中的类型,而不必指定类型的详细命名空间,类似于Java的import,这个功能也是最常用的,几乎每个cs的程序都会用到

  • C#实例解析适配器设计模式

    将一个类的接口变成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够一起工作

  • 使用托管C++粘合C#和C++代码(二)

    本文实现一下C++代码调用C#代码的过程。我构造一个简单并且直观的例子:通过C++ UI 触发C# UI.

  • C#开发高性能Log Help类设计开发

    项目中要在操作数据库的异常处理中加入写Log日志,对于商业上有要求,写log时对其它操作尽可能影响小,不能因为加入log导致耗时太多

  • Async和Await使异步编程更简单

    C#5.0中async和await两个关键字,这两个关键字简化了异步编程,之所以简化了,还是因为编译器给我们做了更多的工作

  • C#开发中的反射机制

    反射的定义:审查元数据并收集关于它的类型信息的能力。元数据(编译以后的最基本数据单元)就是一大堆的表,当编译程序集或者模块时,编译器会创建一个类定义表,一个字段定义表,和一个方法定义表等

  • C#运行时相互关系

    C#运行时相互关系,包括运行时类型、对象、线程栈和托管堆之间的相互关系,静态方法、实例方法和虚方法的区别等等

  • C#协变和逆变

    “协变”是指能够使用与原始指定的派生类型相比,派生程度更大的类型,“逆变”则是指能够使用派生程度更小的类型

  • C#基础概念之延迟加载

    延迟加载(lazy load)是Hibernate3关联关系对象默认的加载方式,延迟加载机制是为了避免一些无谓的性能开销而提出来的,所谓延迟加载就是当在真正需要数据的时候,才真正执行数据加载操作

  • 使用托管C++粘合C#和C++代码(一)

    C#在xml读写,数据库操纵,界面构造等很多方面性能卓越;C++的效率高,是底层开发的必备武器

  • C#中的索引器的简单理解和用法

    C#中的类成员可以是任意类型,包括数组和集合。当一个类包含了数组和集合成员时,索引器将大大简化对数组或集合成员的存取操作

  • 深入C# 序列化(Serialize)、反序列化(Deserialize)

    C#中的序列化和反序列化,序列化是.NET运行时环境用来支持用户定义类型的流化的机制