110

I am doing MongoDB lookups by converting a string to BSON. Is there a way for me to determine if the string I have is a valid ObjectID for Mongo before doing the conversion?

Here is the coffeescript for my current findByID function. It works great, but I'd like to lookup by a different attribute if I determine the string is not an ID.

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

18 回答 18

195

我发现 mongoose 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

这是因为有效 id 在转换为 ObjectId 时不会改变,但如果字符串转换为 objectId 时会发生错误,则会发生变化。

于 2015-03-24T11:08:58.997 回答
95

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

咖啡脚本

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    
}
于 2012-12-13T01:00:14.560 回答
67

✅ 内置解决方案isValidObjectId()> Mongoose 5.7.12

如果您使用的是 Mongoose,我们可以使用 mongoose内置的 isValidObjectId来测试 String 是 12 字节还是 24 十六进制字符的字符串。

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

请注意!

isValidObjectId()最常用于测试预期的 objectID,以避免 mongoose throwing invalid object 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 字符十六进制字符串。

于 2020-08-31T08:13:08.327 回答
12

我过去曾使用本机节点 mongodb 驱动程序来执行此操作。isValid 方法检查该值是否为有效的 BSON ObjectId。请参阅此处的文档。

var ObjectID = require('mongodb').ObjectID;
console.log( ObjectID.isValid(12345) );
于 2014-07-15T16:23:55.490 回答
5

如果字符串包含 12 个字母,mongoose.Types.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
于 2018-08-30T15:29:50.560 回答
4

这是我根据@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;
}
于 2016-03-30T19:21:26.070 回答
2

检查字符串是否为有效的 Mongo ObjectId 的最简单方法是使用mongodb模块。

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

if(ObjectID.isValid(777777777777777)){
   console.log("Valid ObjectID")
}
于 2020-07-17T17:39:22.397 回答
2

我发现的唯一方法是使用我要检查的值创建一个新的 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
于 2018-04-18T13:03:17.853 回答
1

下面是一个函数,它既检查 ObjectIdisValid方法,也检查是否new ObjectId(id)返回相同的值。isValid安迪·麦克劳德(Andy Macleod)在选择的答案中很好地描述了独自一人不够的原因。

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;
}
于 2020-01-30T18:10:05.443 回答
1

@ross-u 的回答真是太棒了。

我已经链接了方法来进行完整的内联验证:

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

请注意双等号,这非常重要,因为new ObjectId()它不返回字符串,并且在与普通字符串(我的逻辑中已经出现)进行比较时,严格比较将返回 false。

这些方法已从mongooserequire 公开的对象中解构:

const {
  Types: {
    ObjectId: { isValid },
    ObjectId
  }
} = require("mongoose");
于 2020-02-28T09:23:35.460 回答
1

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

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 或空 props 以获取新生成的 ID。

于 2019-06-23T08:09:10.340 回答
1

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

if (ObjectId.isValid(stringId) && (ObjectId(stringId).toString() === stringId)){
  // your operation
}
于 2021-07-02T13:14:28.163 回答
0

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.

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.

因此,isValid(...)如果参数是有效的 BSON ObjectId 对象,将返回 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的不是一个有效的ObjectIdHEX 字符串(它没有被构造函数转换),这个方法将返回 false。

于 2022-01-21T12:40:15.393 回答
0

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

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

我只是使用了一个简单的 try catch 来解决这个问题。

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
}
于 2016-09-15T18:14:51.663 回答
0

除了Andy Macleod接受的答案之外,我还创建了一个辅助函数,可用于检查字符串和 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
于 2020-02-27T22:57:02.737 回答
0

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

ObjectId.isValid(ObjectId.createFromHexString(hexId));
于 2016-04-21T22:24:00.143 回答
0

对于 mongoose ,使用 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');
}
于 2017-10-23T05:43:02.347 回答
-2

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

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

于 2014-12-23T23:09:30.267 回答