我可以确定一个字符串是否是 MongoDB ObjectID 吗?

我正在通过将字符串转换为 BSON 来执行 MongoDB 查找。在进行转换之前,是否有办法确定我所拥有的字符串是否是 Mongo 的有效 ObjectID?

下面是我当前 findByID 函数的咖啡脚本。它工作得很好,但是如果我确定字符串不是 ID,我希望通过不同的属性进行查找。

db.collection "pages", (err, collection) ->
collection.findOne
_id: new BSON.ObjectID(id)
, (err, item) ->
if item
res.send item
else
res.send 404
119776 次浏览

您可以使用正则表达式来测试:

咖啡脚本

if id.match /^[0-9a-fA-F]{24}$/
# it's an ObjectID
else
# nope

JavaScript

if (id.match(/^[0-9a-fA-F]{24}$/)) {
// it's an ObjectID
} else {
// nope
}

我过去曾使用本机节点 mongodb 驱动程序来完成这项工作。IsValid 方法检查该值是否为有效的 BSON ObjectId。请参阅这里的文档。

var ObjectID = require('mongodb').ObjectID;
console.log( ObjectID.isValid(12345) );

警告: 对于以有效十六进制数字开头的任意12/24长度字符串,是有效的将返回 没错。 目前我认为这是一个更好的检查:

((thing.length === 24 || thing.length === 12) && isNaN(parseInt(thing,16)) !== true)

我发现猫鼬 ObjectId 验证器可以验证有效的 objectID,但是我发现了一些无效的 id 被认为是有效的情况。(例如: 任何12个字符的长字符串)

var ObjectId = require('mongoose').Types.ObjectId;
ObjectId.isValid('microsoft123'); //true
ObjectId.isValid('timtomtamted'); //true
ObjectId.isValid('551137c2f9e1fac808a5f572'); //true

我一直在做的是将字符串强制转换为 objectId,然后检查原始字符串是否与 objectId 的字符串值匹配。

new ObjectId('timtamtomted'); //616273656e6365576f726b73
new ObjectId('537eed02ed345b2e039652d2') //537eed02ed345b2e039652d2

这是因为当转换为 ObjectId 时,有效 id 不会改变,但是当转换为 objectId 时,获得假有效的字符串会改变。

下面是我根据@andy-macleod 的回答编写的一些代码。

它可以接受 int、 string 或 ObjectId,如果传递的值有效,则返回有效的 ObjectId; 如果传递的值无效,则返回 null:

var ObjectId= require('mongoose').Types.ObjectId;


function toObjectId(id) {


var stringId = id.toString().toLowerCase();


if (!ObjectId.isValid(stringId)) {
return null;
}


var result = new ObjectId(stringId);
if (result.toString() != stringId) {
return null;
}


return result;
}

如果你有十六进制字符串,你可以使用:

ObjectId.isValid(ObjectId.createFromHexString(hexId));

我花了一段时间才得到一个有效的解决方案,因为@Andy Macleod 提出的将 objectId 值与自己的字符串进行比较的解决方案正在使 Express.js 服务器崩溃:

var view_task_id_temp=new mongodb.ObjectID("invalid_id_string"); //this crashed

我只是用了一个简单的尝试捕捉来解决这个问题。

var mongodb = require('mongodb');
var id_error=false;
try{
var x=new mongodb.ObjectID("57d9a8b310b45a383a74df93");
console.log("x="+JSON.stringify(x));
}catch(err){
console.log("error="+err);
id_error=true;
}


if(id_error==false){
// Do stuff here
}

对于 monose,使用 isValid ()函数检查 objectId 是否有效

例如:

var ObjectId = mongoose.Types.ObjectId;
if(ObjectId.isValid(req.params.documentId)){
console.log('Object id is valid');
}else{
console.log('Invalid Object id');
}

我找到的唯一方法是使用我想检查的值创建一个新的 ObjectId,如果输入等于输出,则 id 是有效的:

function validate(id) {
var valid = false;
try
{
if(id == new mongoose.Types.ObjectId(""+id))
valid = true;


}
catch(e)
{
valid = false;
}
return valid;
}


> validate(null)
false
> validate(20)
false
> validate("abcdef")
false
> validate("5ad72b594c897c7c38b2bf71")
true

如果字符串包含12个字母,那么 ObjectID. isValid (string)总是返回 True

let firstUserID = '5b360fdea392d731829ded18';
let secondUserID = 'aaaaaaaaaaaa';


console.log(mongoose.Types.ObjectId.isValid(firstUserID)); // true
console.log(mongoose.Types.ObjectId.isValid(secondUserID)); // true


let checkForValidMongoDbID = new RegExp("^[0-9a-fA-F]{24}$");
console.log(checkForValidMongoDbID.test(firstUserID)); // true
console.log(checkForValidMongoDbID.test(secondUserID)); // false

最简单的方法基本上是将 ObjectId 方法包装在 try and catch 服务中。 然后使用这个服务来处理 ObjecetId,而不是直接使用这个方法:

var ObjectId = REQUIRE OR IMPORT ...


// service
function oid(str) {
try {
return ObjectId(str);
} catch(err) {
return false;
}
}


// usage
if (oid(USER_INPUT)) {
// continue
} else {
// throw error
}

您还可以发送 null 或空道具来获得新生成的 ID。

下面是一个函数,它既检查 ObjectId isValid方法,又检查 new ObjectId(id)是否返回相同的值。isValid不够单独的原因被安迪麦克劳德在选择的答案中描述得很好。

const ObjectId = require('mongoose').Types.ObjectId;


/**
* True if provided object ID valid
* @param {string} id
*/
function isObjectIdValid(id){
return ObjectId.isValid(id) && new ObjectId(id) == id;
}

添加到 Andy Macleod 的 接受的答案中,我创建了一个 helper 函数,它可以用来检查字符串和 ObjectId。

实施:

var ObjectId = require("mongoose").Types.ObjectId;




function isValidObjectId(value) {
// If value is an ObjectId cast it to a string to allow
// passing string or ObjectId as an argument.
var valueString = typeof value === "string" ? value : String(value);
  

// Cast the string to ObjectId
var idInstance = new ObjectId(valueString);


return String(idInstance) === valueString;
}

说明:

在公认的答案中,安迪 · 麦克劳德表示:

我一直在做的是将字符串强制转换为 objectId 和 然后检查原始字符串是否与 ObjectId.


使用无效 ObjectId 字符串

将一个无效的字符串(如 "microsoft")转换为 ObjectId,会得到一个完全不同的值:

        "microsoft"
↓
String( new ObjectId("microsoft")  );
↓
"6d6963726f736f6674313233"
↓
"microsoft" === "6d6963726f736f6674313233" // false

使用有效 ObjectId 字符串

将类似("6d6963726f736f6674313233")的有效字符串转换为 ObjectId,得到相同的值:

"6d6963726f736f6674313233"
↓
String( new ObjectId("6d6963726f736f6674313233") )
↓
"6d6963726f736f6674313233"
↓
"6d6963726f736f6674313233" === "6d6963726f736f6674313233"  // true

@ ross-u 答案太棒了。

我已经将这些方法链接起来,以内联方式进行完整的验证:

documentId = id && isValid(id) && new ObjectId(id) == id ? id : null

注意,双等号非常重要,因为 new ObjectId()不返回字符串,与普通字符串(我在逻辑中提到过)进行比较时,严格比较将返回 false。

这些方法已从根据以下要求公开的 mongoose对象中解构出来:

const {
Types: {
ObjectId: { isValid },
ObjectId
}
} = require("mongoose");

检查字符串是否是有效的 MongoObjectId 的最简单方法是使用 Mongob模块。

const ObjectID = require('mongodb').ObjectID;


if(ObjectID.isValid(777777777777777)){
console.log("Valid ObjectID")
}

在解决方案 isValidObjectId()中构建 > Mongoose 5.7.12

如果您正在使用 Mongoose,我们可以使用 猫鼬内嵌 IsValidObjectId来测试 String 是12字节还是24个十六进制字符的字符串。

执行有效的查询而不抛出任何无效的对象 ID 错误,这就足够了

mongoose.isValidObjectId(string); /* will return true/false */

请注意!

isValidObjectId()最常用于测试期望的 objectID,以避免猫鼬抛出无效的对象 ID 错误。

例子

if (mongoose.isValidObjectId("some 12 byte string")) {
return collection.findOne({ _id: "some 12 byte string" })
// returns null if no record found.
}

如果没有有条件地测试预期的 objectID 是否有效,则需要捕获错误。

try {
return collection.findOne({ _id: "abc" })
//this will throw error
} catch(error) {
console.log('invalid _id error', error)
}

因为 findOne({ _id: null })findOne({ _id: undefined })是完全有效的查询(不会抛出错误) ,所以 isValidObjectId(undefined)isValidObjectId(null)将返回 true。

注意2!

123456789012 可能看起来不像 bson 字符串,但它完全是一个有效的 ObjectID,因为下面的查询 没有抛出错误。(如果没有找到记录,返回 null)。

findOne({ _id: ObjectId('123456789012')}) // ✅ valid query

313233343536373839303132 可能看起来像一个24个字符的字符串(它是 123456789012的十六进制值) ,但它也是一个有效的 ObjectId,因为下面的查询 没有抛出错误。(如果没有找到记录,返回 null)

findOne({ _id: ObjectId('313233343536373839303132')}) // ✅ valid query

以下内容无效(1个字符串字符小于上述示例)

findOne({ _id: ObjectId('12345678901')}) // ❌ not 12 byte string
findOne({ _id: ObjectId('31323334353637383930313')}) // ❌ not 24 char hex

ObjectId 格式

ObjectId 很小,可能是唯一的,生成很快,并且是有序的。 ObjectId 值的长度为12字节,包括:

  • 一个4字节的时间戳值,表示 ObjectId 的创建,以 Unix 纪元以来的秒为单位
  • 每个进程生成一个5字节的 随机值。这个 随机值对于机器和进程来说是独一无二的。
  • 一个3字节的递增计数器,初始化为一个随机值

由于上述 随机值,ObjectId 无法计算。它只能显示为12字节字符串或24个字符的十六进制字符串。

这种方法可能对某些人有帮助,它适用于 nodejs mongodb 驱动程序

if (ObjectId.isValid(stringId) && (ObjectId(stringId).toString() === stringId)){
// your operation
}

Https://mongodb.github.io/node-mongodb-native/api-bson-generated/objectid.html#objectid-isvalid

来自 MongoDB 文档:

构造函数文档:

ObjectID()
Constructor
Create a new ObjectID instance


class ObjectID()
Arguments:
id (string) – Can be a 24 byte hex string, 12 byte binary string or a Number.
Returns:
object instance of ObjectID.

IsValid ()文档:

Checks if a value is a valid bson ObjectId


ObjectID.isValid()
Returns:    boolean return true if the value is a valid bson ObjectId, return false otherwise.

因此,如果参数是有效的 BSON ObjectId 对象,那么 isValid(...)将返回 true,并且构造函数 ObjectId(...)只接受有效的 BSON ObjectId 对象参数(基本上,如果构造函数抛出异常,isValid(...)将返回 false)。

知道这些。我们可以首先检查参数是否是一个有效的 ObjectId,然后创建一个具有该值的 ObjectId并比较 HEX 字符串。

const objectId = 'str_object_id';
const isValid = ObjectId.isValid(objectId) && new ObjectId(objectId).toHexString() == objectId;

如果传递的 objectId不是有效的 ObjectId HEX 字符串(它没有被构造函数转换) ,则此方法将返回 false。

Mongoose 6.2.5引入了 mongoose.isObjectIdOrHexString(),它只在给定的值是 ObjectId实例或表示 ObjectId的24个字符的十六进制字符串时返回 true,并将返回数字、文档和长度为12的字符串的 false(不像 mongoose.isValidObjectId(),它只是 Mongoose 6中 mongoose.Types.ObjectId.isValid()的包装器)

IsObjectIdOrHexString ()

参数

  • 任何

如果给定值是 Mongoose ObjectId (使用 instanceof) ,或者给定值是一个24个字符的十六进制字符串,这是 ObjectId 最常用的字符串表示形式,则返回 true。

这个函数类似于 isValidObjectId () ,但要严格得多,因为对于 Mongoose 可以转换为 ObjectId 的任何值,isValidObjectId ()都将返回 true。其中包括 Mongoose 文档、任何长度为12的字符串和任何数字。IsObjectIdOrHexString ()仅对 ObjectId 实例或24个字符十六进制字符串返回 true,对于长度为12的数字、文档和字符串返回 false。

例子 :

mongoose.isObjectIdOrHexString(new mongoose.Types.ObjectId()); // true
mongoose.isObjectIdOrHexString('62261a65d66c6be0a63c051f'); // true


mongoose.isObjectIdOrHexString('0123456789ab'); // false
mongoose.isObjectIdOrHexString(6); // false
mongoose.isObjectIdOrHexString(new User({ name: 'test' })); // false
mongoose.isObjectIdOrHexString({ test: 42 }); // false

如果不想使用 mongo db 驱动程序或 ORM 导出的函数,可以使用 RegExp 执行一些简单的 objectId 验证:

/[0-9a-f]{24}/i

有关更多信息,请查看 这根线

对于普通的 javscript,这是有帮助的:

const isMongoId = str => {
return str.match(/^[0-9a-fA-F]{24}$/);
};