【问题标题】:Trying to dynamically generate _id in Mongoose, but returns object尝试在 Mongoose 中动态生成 _id,但返回对象
【发布时间】:2013-11-04 12:40:11
【问题描述】:

基本上,我正在尝试计算集合中的文档,并将新文档设置为_id。我尝试了许多组合,但似乎没有一个有效。

这是我尝试过的:

var count = PostModel.find( function( err, posts ) {
    if ( !err ) {
        return posts.length;
    }
    else {
        return console.log( err );
    }
});

var post = new PostModel({
    _id: count,
    title: request.body.title,
    content: request.body.content,
    tags: request.body.tags
});

返回:

{ message: 'Cast to number failed for value "[object Object]" at path "_id"',
  name: 'CastError',
  type: 'number',
  value:
   { options: { populate: {} },
     safe: undefined,
     _conditions: {},
     _updateArg: {},
     _fields: undefined,
     op: 'find',
     model:
      { [Function: model]
        modelName: 'Post',
        model: [Function: model],
        options: undefined,
        db: [Object],
        schema: [Object],
        collection: [Object],
        base: [Object] } },
  path: '_id' }

还有这个:

var post = new PostModel({
    _id: PostModel.find( function( err, posts ) {
        if ( !err ) {
            return posts.length;
        }
        else {
            return console.log( err );
        }
    }),
    title: request.body.title,
    content: request.body.content,
    tags: request.body.tags
});

返回相同的错误。但是,当我单独添加以下内容时,它会记录集合的长度:

PostModel.find( function( err, posts ) {
    if ( !err ) {
        return console.log(posts.length);
    }
    else {
        return console.log( err );
    }
});

我也尝试过以各种方式使用count(),但没有取得任何进展。有关如何查询集合以获取计数并将其设置为 _id 的任何见解都会很有帮助。

【问题讨论】:

标签: node.js mongodb mongoose


【解决方案1】:

首先,在 MongoBD 中不推荐这样做,因为它不能很好地扩展。

但是,如果您真的想这样做,MongoDB 官方文档中有说明 here 提供了一种既安全又好用的方法。

基本上,您使用一个小文档来保存当前序列 ID,每次插入文档时,您都会读取并自动递增该序列。这比每次插入时都计算文档效率要高得多。

使用您的解决方案,如果两个进程同时运行会发生什么情况?您最终可能会得到相同的 ID,因为您的插入和序列生成/计数不是原子的。

编辑:

要从您的模型中获取计数,请使用以下命令:

PostModel.count( function (err, count) {
  if (err) ..
  console.log('there are %d posts', count);
});

由 OP 编辑​​:

根据下面的 cmets,问题在于同步使用异步函数。当所有代码都移到回调函数中时,它就起作用了。这是解决方案:

PostModel.count( function (err, count) {
    if (err)
        console.log(err);
    else {
        console.log('there are %d posts', count);

        var post = new PostModel({
            _id: count,
            title: request.body.title,
            content: request.body.content,
            tags: request.body.tags
        });

        post.save( function( err ) {
            if( !err ) {
                return console.log( 'Post saved');
            } else {
                console.log( err );
            }
        });

        return response.send(post);
    }
});

【讨论】:

  • 感谢您的回复。缩放并不是真正的问题,因为我只是使用 Mongo 来存储我的博客文章,所以我一次只能从一台机器插入,并可能从多台机器读取。您发送给我的链接绝对有帮助,但我正在尝试弄清楚如何在 Mongoose 中使用它。我会考虑调整它,虽然我可能有同样的问题。
  • 提取的关键部分是使用一个小文档来存储序列。在 Mongoose 中,您将执行 findAndModify 以获取当前序列并原子地对其进行迭代。
  • 看看我的更新,希望它能解决你的计数问题
  • 另外,关于扩展:如果您在博客上开始获得大量点击时最终对博客文章进行分片,那么拥有顺序 _id 可能会影响您的阅读时间。例如,您可能想要检索所有最新的博客,如果使用 _id 作为分片键将导致所有查询进入一台机器,如果您使用散列 _id 那么查询将均匀分布在所有碎片。
  • 我对猫鼬了解不多,但看起来您正在尝试以同步方式使用异步回调。您能否将 post = PostModel... 代码嵌入到 count 函数的回调中?
猜你喜欢
  • 2018-07-07
  • 2022-08-03
  • 1970-01-01
  • 2018-02-27
  • 2020-10-27
  • 2013-01-17
  • 2017-02-07
  • 1970-01-01
相关资源
最近更新 更多