LoginSignup
1
1

More than 1 year has passed since last update.

MongoDB・MongooseのObjectIDに関して

Last updated at Posted at 2022-06-07

ObjectIDってなんだ?

MongoDBの_idにデフォルトでセットされる値ですが、文字列(string)ではなく、ObjectIdクラスのインスタンスのようです。

なので、以下に挙げますが、_id同士を単純に比較しても常にfalseになってしまいますし、_idの文字列の値(313263686172313263686172)と_idを比較しても、文字列とインスタンスなので、こちらも常にfalseとなってしまいます。

_idの値の文字列をクエリの検索条件としたい

findById()は引数にstringを受け付けるので、そのまま渡せます。

const result = await UserModel.findById('313263686172313263686172')

集計関数であるaggregate()の中で検索条件としたい場合は、$convertというaggregation演算子を使ってObjectIdインスタンスに変換してあげる必要があります。

以下は、_idの配列のフィールドの中に、特定の_idが含まれているかを検索する例で、他に$inという演算子を使っています。

// 配列のフィールド(memberIds)にuserIdが含まれているTeamを検索
const userId = '313263686172313263686172'
const result = await TeamModel.aggregate([
  $match: {
    $expr: {
      $in: [
        $convert: {
          input: userId,
          to: 'objectId'
        },
       'memberIds'
      ]
    }
  }
])

※ObjectIDへの$convertは以下でもいいらしい。

{
  $toObjectId: userId
}

_id同士の比較

ObjectIdインスタンスの.equals()というメソッドを使用します。

const user = await UserModel.findById('313263686172313263686172')
const team = await TeamModel.findOne({})

// x これだとインスタンス同士の比較なので常にfalseになってしまう
const isTeamMember = team.memberIds.some((memberId) => memberId === user._id)

// o equals()というメソッドを使う
const isTeamMember = team.memberIds.some((memberId) => memberId.equals(user._id))

そのほか

ObjectIds in Mongoose - Mastering JS

Mongooseは24個の16進文字列や任意の12個の文字列(12byteの文字列)はObjectIDインスタンスに変換するようです。

また、ObjectIDの値(の文字列)は12byteの文字列で構成され、最初の4byteはタイムスタンプで、_id.getTimestamp()というメソッドでタイムスタンプの値を取得できるらしい。。。

間違いがありましたら、ぜひご指摘をお願いいたします🙏

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1