MongoDB 3.4新機能:Viewを試してみた

2017.03.24

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、菊池です。

MongoDB の最新バージョン、Ver. 3.4で追加された新機能、Read Only Viewを試してみました。

View

RDBではおなじみのビュー(View)ですが、MongoDBでも Ver. 3.4 からサポートされました。コレクション(RDBの表に相当)に対しビューを使ってアクセスすることで、よく使うクエリの簡略化や不要な情報のフィルタリングが可能です。

Viewの作成

Viewは、db.runCommand()db.createView()db.createCollection()のいずれかのコマンドを実行することで作成が可能です。

db.runCommand( { create: "ビュー名" , viewOn: "ソースコレクション" , pipeline: [ パイプライン ] } )
db.createView( "ビュー名", "ソースコレクション" , [ パイプライン ] )
db.createCollection( "ビュー名", { viewOn: "ソースコレクション", pipeline: [ パイプライン ] })

ビューが実行するクエリはパイプラインで指定します。

やってみた

早速試してみました。サンプルとして公式ドキュメントにあるAggregationの例を使って試しています。

まずはコレクションにデータを入れます。

> db.members.insert({_id : "jane",joined : ISODate("2011-03-02"),likes : ["golf", "racquetball"]});
WriteResult({ "nInserted" : 1 })
> db.members.insert({_id : "joe",joined : ISODate("2012-07-02"),likes : ["tennis", "golf", "swimming"]});
WriteResult({ "nInserted" : 1 })
>
> db.members.find()
{ "_id" : "jane", "joined" : ISODate("2011-03-02T00:00:00Z"), "likes" : [ "golf", "racquetball" ] }
{ "_id" : "joe", "joined" : ISODate("2012-07-02T00:00:00Z"), "likes" : [ "tennis", "golf", "swimming" ] }
>

2件のデータがmembersコレクションにインサートされました。このコレクションに対し、以下のパイプラインでビューを作成します。

  [
    { $project : { name:{$toUpper:"$_id"} , _id:0 } },
    { $sort : { name : 1 } }
  ]

作成します。

> db.runCommand( { create: "membersView_1" , viewOn:"members" , pipeline:[{ $project : { name:{$toUpper:"$_id"} , _id:0 } },{ $sort : { name : 1 } }] } )
{ "ok" : 1 }

作成したビューからデータを参照してみます。通常のコレクションと同様に指定が可能です。

> db.membersView_1.find()
{ "name" : "JANE" }
{ "name" : "JOE" }
>

また、show collectionsを実行すると、通常のコレクションと同様に見えます。

> show collections
members
membersView_1
system.views
>

ぱっと見て、ビューなのかコレクションなのか見分けがつきませんが、db.getCollectionInfos()で確認が可能です。

> db.getCollectionInfos({name:"membersView_1"})
[
       	{
       		"name" : "membersView_1",
       		"type" : "view",
       		"options" : {
       			"viewOn" : "members",
       			"pipeline" : [
       				{
       					"$project" : {
       						"name" : {
       							"$toUpper" : "$_id"
       						},
       						"_id" : 0
       					}
       				},
       				{
       					"$sort" : {
       						"name" : 1
       					}
       				}
       			]
       		},
       		"info" : {
       			"readOnly" : true
       		}
       	}
]
>

ビューであることや、パイプラインの内容も確認できます。

ビューは読み取り専用なので、データのインサートやアップデートはできません。

> db.membersView_1.insert({ "name" : "JILL" })
WriteResult({
       	"nInserted" : 0,
       	"writeError" : {
       		"code" : 166,
       		"errmsg" : "Namespace test.membersView_1 is a view, not a collection"
       	}
})
>

また、ビューに定義されたパイプラインは、ビューへのクエリのタイミングで実行されます。ビューに対する実行計画を確認すると、ソースとなっているコレクションに対する実行計画が確認できます。

> db.membersView_1.find().explain()
{
       	"stages" : [
       		{
       			"$cursor" : {
       				"query" : {

       				},
       				"fields" : {
       					"_id" : 1
       				},
       				"queryPlanner" : {
       					"plannerVersion" : 1,
       					"namespace" : "test.members",
       					"indexFilterSet" : false,
       					"parsedQuery" : {

       					},
       					"winningPlan" : {
       						"stage" : "COLLSCAN",
       						"direction" : "forward"
       					},
       					"rejectedPlans" : [ ]
       				}
       			}
       		},
       		{
       			"$project" : {
       				"_id" : false,
       				"name" : {
       					"$toUpper" : [
       						"$_id"
       					]
       				}
       			}
       		},
       		{
       			"$sort" : {
       				"sortKey" : {
       					"name" : 1
       				}
       			}
       		}
       	],
       	"ok" : 1
}
>

元のコレクションのデータ量やインデックス有無などによってパフォーマンスに影響がありますので、注意して設定しましょう。

さいごに

いかがでしょうか。

MongoDBの最新バージョンである3.4で追加された新機能の、ビューについて紹介しました。よく使うクエリやフィルタしたい情報がある場合には、設定しておくと便利です。特に、オペレーションでよく使うクエリにはビューを設定しておくことで、間違ってフルスキャンがかかり、パフォーマンスに影響が出るようなことも抑止できるかと思います。