传入更新的数字在保存到集合(MongoDB)时会发生更改

时间:2013-12-08 16:30:15

标签: node.js mongodb mongoose

我有一个使用数值作为_id的Mongoose架构,例如102375848308956134094。当我将集合和findById保存在Mongoose或find({ _id: 102375848308956134094 }); Mongo shell中时,会返回正确的文档,但_id与先前提供的文档不同(而不是102375848308956140000 )。

这是一个问题,好像我要保存一个集合_id 102375848308956134095(注意最后一个数字从4更改为5),MongoDB错误输出(E11000 duplicate key error index... dup key: { : 1.023758483089561e+20)。

MongoDB是否将Number视为浮点数?

以下是一个示例查询:

> db.users.find({ _id: 102375848308956134094 }).pretty();
{
    "_id" : 102375848308956140000,
    "access_token" : "",
    "access_token_expires" : ISODate(""),
    "given_name" : "Jonathon",
    "refresh_token" : ""
}

注意:我删除了access_token等值。

但是,当保存该文档时,我绝对将_id值指定为102375848308956134094

任何想法发生了什么?

这是我的架构:

/*jslint es5: true, indent: 2, node:true, nomen: true, maxlen: 80, vars: true*/

'use strict';

module.exports = function (mongoose) {
  var Schema = new mongoose.Schema({
    _id: Number,
    access_token: String,
    access_token_expires: Date,
    given_name: String,
    refresh_token: String
  });

  return mongoose.model('User', Schema);
};

这是upsert

...

models.user.update(
  {
    _id: user.id
  },
  {
    access_token: access_token,
    access_token_expires: new Date(Date.now() + (59 * 60 * 1000)),
    given_name: user.given_name,
    refresh_token: refresh_token
  },
  {
    upsert: true
  },
  /*TODO: Handle upsert errors*/
  function (err, numberAffected, raw) {
    if (err) {
      console.log(err);
    } else {
      delete req.session.state;

      req.session._id = user.id;

      res.redirect('/');
    }
  }
);

...

所有的帮助,一如既往,非常感谢!

/ 修改 /

我已经尝试过@ JohnnyHK使用Long数字的答案,但_id似乎仍未正确存储在文档中。它将_id保存为-8304616133301175602而不是102375848308956134094。我已经对find文档进行了多次查询,但只提供_id作为-8304616133301175602返回正确的文档,例如

> db.users.find().pretty();
{
    "_id" : NumberLong("-8304616133301175602"),
    "access_token" : "ya29.1.AADtN_VyfAvBlam2HCERpI0JcJkcwg22t1124tZw0G7pgRyTcaIuGU-dX3H4Q-M",
    "access_token_expires" : ISODate("2013-12-09T12:42:53.098Z"),
    "given_name" : "Jonathon",
    "refresh_token" : "1/-2GQ_s3JogCr45Z1CBKWBHTEcjE0Nda9xkpFFdl7wT0"
}
> db.users.find({ _id: 102375848308956134094 }).pretty();
> db.users.find({ _id: NumberLong(102375848308956134094) }).pretty();
> db.users.find({ _id: NumberLong('102375848308956134094') }).pretty();
Mon Dec  9 11:46:26.433 Error: could not convert "102375848308956134094" to NumberLong
> db.users.find({ _id: -8304616133301175602 }).pretty();
{
    "_id" : NumberLong("-8304616133301175602"),
    "access_token" : "",
    "access_token_expires" : ISODate(""),
    "given_name" : "Jonathon",
    "refresh_token" : ""
}

有关为何会这样做的任何想法?

1 个答案:

答案 0 :(得分:0)

Number模式类型是64位浮点数,它没有足够的分辨率来准确表示102375848308956134094,因此它最终舍入为102375848308956140000。

一种解决方案是使用mongoose-long插件(由Mongoose的作者创建),以便您可以为_id使用64位整数,如下所示:

var Schema = new mongoose.Schema({
    _id: {SchemaTypes.Long},
    access_token: String,
    access_token_expires: Date,
    given_name: String,
    refresh_token: String
});

<强>更新

您的数字_id值实际上大于64位,因此如果您不能将它们缩小,则必须使用字符串。

var Schema = new mongoose.Schema({
    _id: String,
    access_token: String,
    access_token_expires: Date,
    given_name: String,
    refresh_token: String
});