查找 ObjectId _id 但 Schema 已将 _id 定义为 String
Find ObjectId _id but Schema has defined _id as String
以前我没有在我的架构中声明 _id
,因此每个新提交自然会生成 MongoDB ObjectId
,因为它是 _id
。但是,要求已更改,现在 _id
声明为 String
,如下所示。
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var MySchema = new Schema({
_id: {
type: String,
},
schoolID: {
type: mongoose.Schema.Types.ObjectId, ref: 'School'
},
points: {
type: Number
},
});
MySchema.index({ schoolID : 1})
module.exports = mongoose.model('Submission', MySchema);
但是,现在我根本无法使用 _id
找到我之前插入的文档。我试过了
var submissionId = "60654319a8062f684ac8fde4"
Submission.findOne({ _id: mongoose.mongo.ObjectId(submissionId ) })
Submission.findOne({ _id: mongoose.Types.ObjectId(submissionId ) })
Submission.findOne({ _id: mongoose.ObjectId(submissionId ) })
但它总是 return null
。所以当我用var mongoose = require('mongoose').set('debug', true);
查看的时候,会显示在下面;我上面的所有查询仍然会发现使用 String
,而不是 ObjectId
Mongoose: submission.findOne({ _id: '60654319a8062f684ac8fde4' }, { projection: {} })
问题 - _id: { type: String,},
mongoose 会在查询数据库之前转换该值,因此在您的情况下,它将始终是一个字符串。
选项-1
将旧的 objectId 转换为字符串,因为您打算使用字符串 _id
,因此最好保持一致。
运行 这些命令来自 shell, Robomongo
这将为现有 ObjectId
条记录添加字符串 _id
的记录。
db.collection.find({}).toArray() // loop all records
.forEach(function (c) {
if (typeof c._id !== 'string') { // check _id is not string
c._id = c._id.str; db.collection.save(c); // create new record with _id as string value
}
});
删除 ObjectId
的记录
db.collection.remove({ _id: { $type: 'objectId' } })
选项-2
添加 Mongoose 自定义类型。
https://mongoosejs.com/docs/customschematypes.html
class StringOrObjectId extends mongoose.SchemaType {
constructor(key, options) {
super(key, options, 'StringOrObjectId');
}
convertToObjectId(v) {
const checkForHexRegExp = new RegExp("^[0-9a-fA-F]{24}$");
let _val;
try {
if (checkForHexRegExp.test(v)) {
_val = mongoose.Types.ObjectId(v);
return _val;
}
} catch (e) {
console.log(e);
}
}
convertToString(v) {
let _val = v;
try {
if(_.isString(_val)) return _val;
if(_.isNumber(_val)) return _.toString(_val);
} catch (e) {
console.log(e);
}
}
cast(val) {
const objectIdVal = this.convertToObjectId(val);
if (objectIdVal) return objectIdVal;
const stringVal = this.convertToString(val)
if (stringVal) return stringVal;
throw new Error('StringOrObjectId: ' + val +
' Nor string nor ObjectId');
}
}
mongoose.Schema.Types.StringOrObjectId = StringOrObjectId;
var MySchema = new Schema({
_id: {
type: StringOrObjectId, // custom type here
},
schoolID: {
type: mongoose.Schema.Types.ObjectId, ref: 'School'
},
points: {
type: Number
},
});
查询
Submission.findOne({ _id: submissionId }); // it will cast ObjectId or String or throw error
缺点
- 如果你的 _id 类型字符串是
60516ae1ef682d2804a2fa72
就像有效的 ObjectId
它将转换为 ObjectId
这将与记录不匹配。
注意 - 这是一个粗略的 class StringOrObjectId
添加适当的检查并正确测试。
选项-3
简单方法 - 使用 mongoose.Mixed
https://mongoosejs.com/docs/schematypes.html#mixed
https://mongoosejs.com/docs/api.html#mongoose_Mongoose-Mixed
cont MySchema = new Schema({
_id: {
type: mongoose.Mixed,
},
schoolID: {
type: mongoose.Schema.Types.ObjectId, ref: 'School'
},
points: {
type: Number
},
});
在 mongoose 中没有直接的方法来处理这种情况,
Mongoose 在发送命令之前转换过滤器以匹配模型的架构。有关 Mongoose 如何转换过滤器的更多信息,请参阅 query casting tutorial。
你可以试试custom schema types,
class StrOrObjId extends mongoose.SchemaType {
constructor(key, options) {
super(key, options, 'StrOrObjId');
}
cast(val) {
if (typeof val !== 'string' && !mongoose.Types.ObjectId.isValid(val)) {
throw new Error('StrOrObjId: ' + val + ' must be a String or ObjectId');
}
return val;
}
}
// Don't forget to add `StrOrObjId` to the type registry
mongoose.Schema.Types.StrOrObjId = StrOrObjId;
比在 _id
字段中使用该类型,
var MySchema = new Schema({
_id: {
type: StrOrObjId,
},
schoolID: {
type: mongoose.Schema.Types.ObjectId, ref: 'School'
},
points: {
type: Number
}
});
以前我没有在我的架构中声明 _id
,因此每个新提交自然会生成 MongoDB ObjectId
,因为它是 _id
。但是,要求已更改,现在 _id
声明为 String
,如下所示。
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var MySchema = new Schema({
_id: {
type: String,
},
schoolID: {
type: mongoose.Schema.Types.ObjectId, ref: 'School'
},
points: {
type: Number
},
});
MySchema.index({ schoolID : 1})
module.exports = mongoose.model('Submission', MySchema);
但是,现在我根本无法使用 _id
找到我之前插入的文档。我试过了
var submissionId = "60654319a8062f684ac8fde4"
Submission.findOne({ _id: mongoose.mongo.ObjectId(submissionId ) })
Submission.findOne({ _id: mongoose.Types.ObjectId(submissionId ) })
Submission.findOne({ _id: mongoose.ObjectId(submissionId ) })
但它总是 return null
。所以当我用var mongoose = require('mongoose').set('debug', true);
查看的时候,会显示在下面;我上面的所有查询仍然会发现使用 String
,而不是 ObjectId
Mongoose: submission.findOne({ _id: '60654319a8062f684ac8fde4' }, { projection: {} })
问题 - _id: { type: String,},
mongoose 会在查询数据库之前转换该值,因此在您的情况下,它将始终是一个字符串。
选项-1
将旧的 objectId 转换为字符串,因为您打算使用字符串 _id
,因此最好保持一致。
运行 这些命令来自 shell, Robomongo
这将为现有 ObjectId
条记录添加字符串 _id
的记录。
db.collection.find({}).toArray() // loop all records
.forEach(function (c) {
if (typeof c._id !== 'string') { // check _id is not string
c._id = c._id.str; db.collection.save(c); // create new record with _id as string value
}
});
删除 ObjectId
db.collection.remove({ _id: { $type: 'objectId' } })
选项-2
添加 Mongoose 自定义类型。
https://mongoosejs.com/docs/customschematypes.html
class StringOrObjectId extends mongoose.SchemaType {
constructor(key, options) {
super(key, options, 'StringOrObjectId');
}
convertToObjectId(v) {
const checkForHexRegExp = new RegExp("^[0-9a-fA-F]{24}$");
let _val;
try {
if (checkForHexRegExp.test(v)) {
_val = mongoose.Types.ObjectId(v);
return _val;
}
} catch (e) {
console.log(e);
}
}
convertToString(v) {
let _val = v;
try {
if(_.isString(_val)) return _val;
if(_.isNumber(_val)) return _.toString(_val);
} catch (e) {
console.log(e);
}
}
cast(val) {
const objectIdVal = this.convertToObjectId(val);
if (objectIdVal) return objectIdVal;
const stringVal = this.convertToString(val)
if (stringVal) return stringVal;
throw new Error('StringOrObjectId: ' + val +
' Nor string nor ObjectId');
}
}
mongoose.Schema.Types.StringOrObjectId = StringOrObjectId;
var MySchema = new Schema({
_id: {
type: StringOrObjectId, // custom type here
},
schoolID: {
type: mongoose.Schema.Types.ObjectId, ref: 'School'
},
points: {
type: Number
},
});
查询
Submission.findOne({ _id: submissionId }); // it will cast ObjectId or String or throw error
缺点
- 如果你的 _id 类型字符串是
60516ae1ef682d2804a2fa72
就像有效的ObjectId
它将转换为ObjectId
这将与记录不匹配。
注意 - 这是一个粗略的 class StringOrObjectId
添加适当的检查并正确测试。
选项-3
简单方法 - 使用 mongoose.Mixed
https://mongoosejs.com/docs/schematypes.html#mixed
https://mongoosejs.com/docs/api.html#mongoose_Mongoose-Mixed
cont MySchema = new Schema({
_id: {
type: mongoose.Mixed,
},
schoolID: {
type: mongoose.Schema.Types.ObjectId, ref: 'School'
},
points: {
type: Number
},
});
在 mongoose 中没有直接的方法来处理这种情况,
Mongoose 在发送命令之前转换过滤器以匹配模型的架构。有关 Mongoose 如何转换过滤器的更多信息,请参阅 query casting tutorial。
你可以试试custom schema types,
class StrOrObjId extends mongoose.SchemaType {
constructor(key, options) {
super(key, options, 'StrOrObjId');
}
cast(val) {
if (typeof val !== 'string' && !mongoose.Types.ObjectId.isValid(val)) {
throw new Error('StrOrObjId: ' + val + ' must be a String or ObjectId');
}
return val;
}
}
// Don't forget to add `StrOrObjId` to the type registry
mongoose.Schema.Types.StrOrObjId = StrOrObjId;
比在 _id
字段中使用该类型,
var MySchema = new Schema({
_id: {
type: StrOrObjId,
},
schoolID: {
type: mongoose.Schema.Types.ObjectId, ref: 'School'
},
points: {
type: Number
}
});