今回は「MongoDB で 検索結果から不要なフィールドを削除する方法」についてまとめます。
どちらかというと「_id が余計なのでこれだけ削除した結果を取得したい」ことが一番多いような気がしますが、
今回は一般化させてどんな加工(今回は削除にフォーカス)ができるのかをまとめます。
MongoDB で 検索結果を加工する場合 aggregate() の $project ステージ で行います。
基本的に削除したいフィールドは 0 指定、表示したいフィールドは 1 指定でできます。
以下で詳しく紹介します。
概要
検索結果のフィールド情報を操作したい場合、 aggregate() の $project ステージ で操作します。
表示したい場合 <フィールド名>: 1 を指定し、非表示にしたい場合は <フィールド名>: 0 を指定します。
ただし、 _id フィールド だけは特殊なフィールドで、明示的に非表示指定がない限りデフォルトで表示されるフィールドになります。
では、以下で具体的なサンプルコードを見ていきましょう。
前提データ
以下のデータを mongo コマンドで投入してある状態で各 fruits について結果取得をどう加工していくか見ていきます。
> db.fruits.insertMany([
{ code: "0101", name: "apple", price: 120 },
{ code: "0201", name: "banana", price: 180 },
{ code: "0301", name: "orange", price: 130 },
{ code: "0302", name: "grapefruit", price: 150 },
{ code: "0401", name: "persimmon", price: 100 },
{ code: "0102", name: "pear", price: 130 },
]);
「削除したいフィールド」を指定する
_id フィールド だけは明示的に削除することを指定しなければデフォルトで表示されるフィールドになります。
_id 以外のフィールドについては表示したくないフィールドに対して aggregate() の $project ステージで 0 を指定すると非表示にできます。
以下のサンプルコードでは _id と code フィールドを非表示にするよう指定しています。
コード (index.js)
var MongoClient = require("mongodb").MongoClient;
var URL = "mongodb://localhost:27017/test";
MongoClient.connect(URL, (err, client) => {
var db = client.db("test");
db.collection("fruits").aggregate([
{ $project: { _id: 0, code: 0 } }
]).toArray()
.then((docs) => {
console.log(docs);
})
.catch((err) => {
console.log(err);
})
.then(() => {
client.close();
});
});
実行 & 結果
> node .\index.js
[ { name: 'apple', price: 120 },
{ name: 'banana', price: 180 },
{ name: 'orange', price: 130 },
{ name: 'grapefruit', price: 150 },
{ name: 'persimmon', price: 100 },
{ name: 'pear', price: 130 } ]
「表示したいフィールド」を指定する
前述の「削除したいフィールド」を指定とは逆で、「表示したいフィールド」を指定することで表示したいフィールドのみを指定することもできます。
以下のサンプルコードでは name のみを表示するよう指定しています。
コード (index.js)
var MongoClient = require("mongodb").MongoClient;
var URL = "mongodb://localhost:27017/test";
MongoClient.connect(URL, (err, client) => {
var db = client.db("test");
db.collection("fruits").aggregate([
{ $project: { name: 1 } }
]).toArray()
.then((docs) => {
console.log(docs);
})
.catch((err) => {
console.log(err);
})
.then(() => {
client.close();
});
});
実行 & 結果
> node .\index.js
[ { _id: 5a5b09ccf43c88db76c7231b, name: 'apple' },
{ _id: 5a5b09ccf43c88db76c7231c, name: 'banana' },
{ _id: 5a5b09ccf43c88db76c7231d, name: 'orange' },
{ _id: 5a5b09ccf43c88db76c7231e, name: 'grapefruit' },
{ _id: 5a5b09ccf43c88db76c7231f, name: 'persimmon' },
{ _id: 5a5b09ccf43c88db76c72320, name: 'pear' } ]
実行結果を見ると分かりますが _id が表示されています。
「概要」でも触れた通り _id は明示的に指定しないとデフォルトで表示されます。
_id も表示せず name のみを返却するようにしたいのであれば $project ステージにおいて { _id: 0, name: 1 } を指定します。
条件付きで「削除したいフィールド」を指定する(?)
MongoDB では条件によってフィールドを削除するといったことができると記載があります(MongoDB - $project (aggregation) Conditionally Exclude Fields)。
これには $cond オペレーター と REMOVE グローバル変数 を利用して実現する…と。
…が、残念ながら実行すると以下のようなエラーが発生します。 mongo コマンドから実行しても MongoDB Node.js Drive から実行しても同じエラー(Use of undefined variable: REMOVE)が出ました。
コード (index.js)
var MongoClient = require("mongodb").MongoClient;
var URL = "mongodb://localhost:27017/test";
MongoClient.connect(URL, (err, client) => {
var db = client.db("test");
db.collection("fruits").aggregate([
{
$project: {
_id: 0,
price: {
$cond: {
if: { $lt: ["$price", 130] },
then: "$$REMOVE",
else: "$price"
}
}
}
}
]).toArray()
.then((docs) => {
console.log(docs);
})
.catch((err) => {
console.log(err);
})
.then(() => {
client.close();
});
});
実行 & 結果(エラーメッセージ)
> node .\index.js
{ MongoError: Use of undefined variable: REMOVE
at queryCallback (c:\work\sample\node_modules\mongodb-core\lib\cursor.js:223:25)
at c:\work\sample\node_modules\mongodb-core\lib\connection\pool.js:541:18
at _combinedTickCallback (internal/process/next_tick.js:73:7)
at process._tickCallback (internal/process/next_tick.js:104:9)
name: 'MongoError',
message: 'Use of undefined variable: REMOVE',
ok: 0,
「特定条件でフィールド削除する」方法はマニュアルの記載通りではうまくいかなそうなので、あきらめて「そのまま空欄出力して判定」したほうが現実的な実装になりそうです。
今回は「MongoDB で 検索結果から不要なフィールドを削除する方法」についてまとめました。 ポイントは以下の通りです。
- aggregate() の $project で表示フィールド制御
- 1で表示、0で非表示
- _id は明示的に非表示指定がなければ常に表示
参考になったでしょうか? 本記事がお役に立っていると嬉しいです!!
最後に… このブログに興味を持っていただけた方は、 ぜひ 「Facebookページ に いいね!」または 「Twitter の フォロー」 お願いします!!