2020年7月5日日曜日

MongoDBで "_id" フィールドの値で検索する

MongoDBにこういうデータがあって、findOneでIDを指定してこの1件を取得したい。

{
    "_id": {
        "$oid": "5f00f8d2e2b54b54646cac19"
    },
    "title": "new book"
}

最初こんな感じで書いてみたけどダメだった。検索結果がnullになってしまう。

var bookid =  '5f00f8d2e2b54b54646cac19';

// NG例1
collection.findOne({ "_id": bookid }, function(err, doc){ 
  // do something
}

// NG例2
collection.findOne({ "_id": { "$oid": bookid } }, function(err, doc){ 
  // do something
}

NG例2の時に MongoError: unknown operator: $oid というエラーが返ってきていたのでこのエラーメッセージで検索して、下記のStackOverflowを発見。

MongoDB: Can't canonicalize query: BadValue unknown operator - Stack Overflow
https://stackoverflow.com/questions/30646068/mongodb-cant-canonicalize-query-badvalue-unknown-operator

You need to convert the id string to an ObjectId like this:
db.guardian.find({ "_id": ObjectId("546b79a2e4b0f7bfbaa97cc7") })

解決した方法

検索条件にIDの文字列ではなく ObjectId(IDの文字列) を指定したらうまくいきました。


var ObjectId = require('mongodb').ObjectID;

// 中略

var bookid =  '5f00f8d2e2b54b54646cac19';

collection.findOne({ "_id": ObjectId(bookid) }, function(err, doc){ 
  // do something
}

MongoDBと接続する部分の全体はこんな感じ

MongoClient.connect(MONGODB_CONNECTION_STRING, function(err, client){
  var db = client.db('personal-library');
  var collection = db.collection('books');
  collection.findOne({ "_id": ObjectId(bookid) }, function(err, doc){
    if (err) {
      console.error(err);
    } else {
      res.json(doc);
    }
    db.close();
  });
});

$oid フィールドに '"f00f8d2e2b54b54646cac19" というStringが格納されてるのではなくて、{ "$oid": "5f00f8d2e2b54b54646cac19" } のひとかたまりでObjectIDクラスのインスタンスを表しているということみたい。(違ったら教えてください)
MongoDBで使用されている拡張書式のようです。

Node.jsを使用している場合、 var ObjectId = require('mongodb').ObjectID; も必要です。上記のStackOverflowのコメントにありました。

If you're using nodejs then you also need to require ObjectID with var ObjectId = require('mongodb').ObjectID;

freeCodeCampのプロジェクトのboilerplateには既に含まれてました。(freeCodeCampやっててこれに行き当たりました)

参考
MongoDB Extended JSON (v2) — MongoDB Manual
https://docs.mongodb.com/manual/reference/mongodb-extended-json/#bson.ObjectId

JSON can only directly represent a subset of the types supported by BSON. To preserve type information, MongoDB adds the following extensions to the JSON format.

ObjectID() — MongoDB Node.JS Driver 1.4.9 documentation
https://mongodb.github.io/node-mongodb-native/api-bson-generated/objectid.html

0 件のコメント:

コメントを投稿