确定性地对MongoDB集合进行排序(添加新的ObjectID字段)

时间:2015-01-14 17:01:43

标签: mongodb sorting objectid database

我正在开发一个MongoDB项目,该项目存储推文并由其他人创建。 这个人决定在MongoDB中使用Twitter推文ID作为_id字段,这意味着我现在无法确定性地对推文进行排序。

示例:

> db.tweets.find().sort({_id : 1}).limit(4)
{'message' : '...', 'userId' : NumberLong(123), '_id' : NumberLong(1)}
{'message' : '...', 'userId' : NumberLong(123), '_id' : NumberLong(2)}
{'message' : '...', 'userId' : NumberLong(123), '_id' : NumberLong(3)}
{'message' : '...', 'userId' : NumberLong(123), '_id' : NumberLong(5)}

对字段ID进行排序的原因是非确定性的,在以后,我的系统可以将ID为4的现有推文添加到数据库中,这意味着相同的命令会给出不同的结果集:

> db.tweets.find().sort({_id : 1}).limit(4)
{'message' : '...', 'userId' : NumberLong(123), '_id' : NumberLong(1)}
{'message' : '...', 'userId' : NumberLong(123), '_id' : NumberLong(2)}
{'message' : '...', 'userId' : NumberLong(123), '_id' : NumberLong(3)}
{'message' : '...', 'userId' : NumberLong(123), '_id' : NumberLong(4)}

我的问题是:有没有办法添加新的'字段'对于集合中的每个条目,其值为ObjectID,以便我可以对其进行排序? 或者,如果没有,建议将用于重命名' _id字段说出tweetId,然后创建_id类型的ObjectID字段

由于

2 个答案:

答案 0 :(得分:1)

实际更改_id字段的唯一方法是复制文档,更改_id,然后删除旧文档,如以下答案所述:

How update the _id of one MongoDB Document?

要简单地添加一个新字段,将更新函数传递给游标的forEach函数应该有效:

db.tweets.find().forEach( 
   function (tweet) {
      db.tweets.update({_id: tweet._id}, {$set: {newFieldName: tweet._id}});
   }
);

答案 1 :(得分:0)

Shawn链接的帖子中的一些片段有几个缺陷。虽然这个想法是正确的,但使用命令行mongo可能会导致一些问题。

mongo中很难在添加任何新推文之前获取所有推文的“快照”。我能找到的唯一方法是使用:

$ db.tweets.find({}, {_id : 1}).toArray()

或者

$ db.tweets.distinct('_id')

不幸的是,由于我的数据库中有超过200万条推文,导致mongo内存不足。我有一个"exception: distinct too big, 16mb cap"错误, 相反,我使用了Python,这是脚本:

#!/usr/bin/env python

"""A tool to work through all tweets, and convert the '_id'
from the Tweet ID into an ObjectID (saving the tweet)
ID in the 'tweetID' field
"""
import pymongo
from bson.objectid import ObjectId

if __name__ == "__main__":
    client = pymongo.MongoClient()
    db = client.guaiamum

    ids = list(t['_id'] for t in db.tweets.find({'_id': {'$type' : 18}}, {'_id' : 1}))
    for _id in ids:
        tweet = db.tweets.find_one({'_id' : _id})
        tweet['_id'] = ObjectId()
        tweet['twitterId'] = _id
        db.tweets.insert(tweet)
        db.tweets.remove(_id, multi=False)

运行仍需要1.5小时,但奇怪的是,它仍然比使用mongo

快得多