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

Sorting MongoDB collection deterministically (add new ObjectID field)

我正在开发一个 MongoDB 项目,该项目存储推文并由其他人创建。 此人决定将 Twitter 推文 ID 用于 MongoDB 中的 _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)}

我的问题是:有没有办法向集合中的每个条目添加一个新的 'field',值类型为 ObjectID,以便我可以对其进行排序? 或者,如果不是,建议 'renaming' _id 字段说 tweetId 然后使 _id 字段类型为 ObjectID

谢谢

实际更改 _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}});
   }
);

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

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

$ 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

快得多