2013-12-08 3 views
0

У меня есть схема Mongoose, которая использует числовое значение как _id, например. 102375848308956134094. Когда я сохраняю коллекцию и findById в Mongoose или find({ _id: 102375848308956134094 }); в оболочке Mongo, верный документ возвращается, хотя _id отличается от ранее предоставленного (вместо него 102375848308956140000).Число, внесенное в обновление при сохранении в коллекции (MongoDB)

Это проблема, как если бы я, чтобы сохранить коллекцию в _id102375848308956134095 (обратите внимание на последнюю цифру изменилось от 4 к 5), MongoDB ошибки из (E11000 duplicate key error index... dup key: { : 1.023758483089561e+20).

Is 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" : "" 
} 

Любые мысли относительно того, почему это может быть?

ответ

0

Number тип схемы является 64-битной плавающей точкой, которая не имеет достаточного разрешения, чтобы точно представлять 102375848308956134094, так что в конце концов округляется до 102375848308956140000.

Одним из решений является использование mongoose-long плагин (созданный автором Мангуста), так что вы можете использовать 64-разрядное целое число для вашего _id так:

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

UPDATE

Ваши числовые значения _id на самом деле больше 64 бит, поэтому вам придется использовать строку вместо этого, если вы не можете сделать их меньше.

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

Я как бы думал, что-то подобное происходит. Благодаря! Будет ли это причиной каких-либо проблем для хранения _id как строки. Кроме того, очевидно, что ошибки не будут выбрасываться, если я попытаюсь вставить строку. Я не делаю никаких вычислений по номеру, поэтому я не вижу проблемы, кроме проблемы с производительностью? Я исхожу из фона MySQL, в котором могут влиять разные типы данных, потребляющих различное пространство и производительность. Любые мысли по этому поводу? –

+0

@JonathonOates Хранение его как строки будет работать нормально, но оно будет намного менее эффективным, так как это 2 байта на символ; так что 42 байта вместо 8 для 64-битного целого. Вы все равно можете передавать значения Long в виде строк, и Mongoose будет конвертировать для вас, когда вы фактически взаимодействуете с БД, поэтому я бы пошел с Long. – JohnnyHK

+0

'Long' 'появляется', который будет неправильно храниться в коллекции, и я не могу' find' запись, если я не запрошу точный (неправильный) номер, сохраненный как '_id'. Я отредактирую свой вопрос с примера :-) –

Смежные вопросы