MongoDB(8) - 検索編

今回から検索に関する動作を確認していきます。

サンプルデータ

次のようなデータがcol1コレクションに設定されています。

nameage
岡田30
山岡35
鈴木24

全件検索・全フィールド表示

もっともシンプルな全件検索、全フィールド表示を行います。

(find関数に引数を設定しません)

[Mongoシェル]

1
2
3
4
> db.col1.find()
{ "_id" : ObjectId("611f72364894370583f311e6"), "name" : "岡田", "age" : 30 }
{ "_id" : ObjectId("611f72364894370583f311e7"), "name" : "山岡", "age" : 35 }
{ "_id" : ObjectId("611f72364894370583f311e8"), "name" : "鈴木", "age" : 24 }

全件検索・フィールド表示/非表示

全件検索は同じで、表示するフィールドを指定してみます。

[Mongoシェル]

1
2
3
4
5
6
7
8
9
10
11
# _idフィールドを非表示
> db.col1.find({},{_id:0})
{ "name" : "岡田", "age" : 30 }
{ "name" : "山岡", "age" : 35 }
{ "name" : "鈴木", "age" : 24 }

# _idフィールドを非表示にし、nameフィールドを表示する
> db.col1.find({},{_id:0,name:1})
{ "name" : "岡田" }
{ "name" : "山岡" }
{ "name" : "鈴木" }

find関数に指定している引数の意味は次の通りです。

  • 第1引数
    検索条件を指定します。カラの場合は全てのドキュメントを表示します。
  • 第2引数
    表示するフィールドを指定します。
    表示するフィールドの場合は1、表示しないフィールドの場合は0を指定します。

Pythonで操作

上記の操作をPythonで行うと、次のようになります。

[ソースコード]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pymongo import MongoClient

# MongoDB操作用のインスタンスを作成
client = MongoClient() # [IPとポートを指定する場合] MongoClient('10.200.243.203', 27017')

# データベースの取得
db1 = client.db1

# 全件表示
for doc in db1.col1.find():
print(doc)

# _idフィールドを非表示
for doc in db1.col1.find({},{'_id':0}):
print(doc)

# _idフィールドを非表示にし、nameフィールドを表示する
for doc in db1.col1.find({},{'_id':0, 'name':1}):
print(doc)

次回は条件(完全一致、部分一致)を指定して、検索の動作確認を行います。

MongoDB(7) - ドキュメント作成編(3回目)

今回はオブジェクト型のドキュメント追加を行ってみます。

オブジェクト型のドキュメント追加

オブジェクト型のドキュメントを追加します。

[Mongoシェル]

1
2
3
4
5
6
7
8
9
10
11
12
13
> db.col1.insertOne({name:"親",
child1: {name:"ゆめ", age:2},
child2: {name:"きぼう", age:1}})
{
"acknowledged" : true,
"insertedId" : ObjectId("611ec366681d069119256981")
}

> db.col1.find()
{ "_id" : ObjectId("611ec366681d069119256981"),
"name" : "親",
"child1" : { "name" : "ゆめ", "age" : 2 },
"child2" : { "name" : "きぼう", "age" : 1 } }

配列の中にオブジェクトがあるドキュメント追加

配列の中にオブジェクトがあるドキュメントを追加します。

[Mongoシェル]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
> db.col1.insertOne({name:"親",
children:[ {name:"ゆめ", age:2},
{name:"きぼう", age:1}]
})
{
"acknowledged" : true,
"insertedId" : ObjectId("611ec3ad681d069119256982")
}

> db.col1.find()
{ "_id" : ObjectId("611ec3ad681d069119256982"),
"name" : "親",
"children" : [ { "name" : "ゆめ", "age" : 2 },
{ "name" : "きぼう", "age" : 1 } ] }

Pythonで操作

上記の操作をPythonでまとめて行うと、次のようになります。

辞書型のデータを追加だけなのでとても簡単です。

[ソースコード]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from pymongo import MongoClient

# MongoDB操作用のインスタンスを作成
client = MongoClient() # [IPとポートを指定する場合] MongoClient('10.200.243.203', 27017')

# データベースの取得
db1 = client.db1

# オブジェクト型のドキュメント追加
doc = {}
doc['name'] = '親'
doc['child1'] = {'name':'ゆめ', 'age':2}
doc['child2'] = {'name':'きぼう', 'age':1}
db1.col1.insert_one(doc)

# 全件表示
for x in db1.col1.find():
print(x)

# 配列の中にオブジェクトがあるドキュメント追加
doc = {}
doc['name'] = '親'
doc['children'] = []
doc['children'].append({'name':'ゆめ', 'age':2})
doc['children'].append({'name':'きぼう', 'age':1})
db1.col1.insert_one(doc)

# 全件表示
for x in db1.col1.find():
print(x)

Pythonでは辞書型がとても便利でよく使うと思いますが、その辞書型をさくさくとDBに追加できるMongoDBはとても相性のいいデータベースだと感じました。

次回からは検索に関する操作を行います。

MongoDB(6) - ドキュメント作成編(2回目)

今回はいろいろなデータ型のドキュメントと配列データをもつドキュメントの追加を行ってみます。

いろいろなデータ型のドキュメント追加

いろいろなデータ型のドキュメントを追加します。

[Mongoシェル]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
> db.col1.insertOne({stringData:"stringData",
doubleData:123.456,
intData:NumberInt(11),
longData:NumberLong(22),
decimalData:NumberDecimal(33.44),
dateData:ISODate("2021-10-10T12:34:56Z"),
booleanData:true,
nullData:null})
{
"acknowledged" : true,
"insertedId" : ObjectId("611c6dd47466ff972f94ccca")
}

> db.col1.find()
{ "_id" : ObjectId("611c6dd47466ff972f94ccca"),
"stringData" : "stringData",
"doubleData" : 123.456,
"intData" : 11,
"longData" : NumberLong(22),
"decimalData" : NumberDecimal("33.4400000000000"),
"dateData" : ISODate("2021-10-10T12:34:56Z"),
"booleanData" : true,
"nullData" : null }

配列データをもつドキュメントを追加

配列データをもつドキュメントを追加します。

(データ追加前にcol1コレクションを一旦削除しています。)

[Mongoシェル]

1
2
3
4
5
6
7
8
9
10
11
> db.col1.drop()
true

> db.col1.insertOne({name:"親", children: ["子1", "子2"]})
{
"acknowledged" : true,
"insertedId" : ObjectId("611c704a7466ff972f94cccb")
}

> db.col1.find()
{ "_id" : ObjectId("611c704a7466ff972f94cccb"), "name" : "親", "children" : [ "子1", "子2" ] }

Pythonで操作

上記の操作をPythonでまとめて行うと、次のようになります。

[ソースコード]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
from pymongo import MongoClient
import bson
from datetime import datetime

# MongoDB操作用のインスタンスを作成
client = MongoClient() # [IPとポートを指定する場合] MongoClient('10.200.243.203', 27017')

# データベースの取得
db1 = client.db1

# いろいろなデータ型のドキュメント追加
data1 = {'stringData' : 'stringData',
'doubleData' : 123.456,
'intData' : 11,
'longData' : bson.int64.Int64('22'),
'decimalData': bson.decimal128.Decimal128('33.44'),
'dateData' : datetime(2021, 10, 10, 12, 34, 56),
'booleanData': True,
'nullData' : None}
db1.col1.insert_one(data1)

# 全件表示
for x in db1.col1.find():
print(x)

# 配列データをもつドキュメント追加
data1 = {'name':'親', 'children': ['子1', '子2']}
db1.col1.insert_one(data1)

# 全件表示
for x in db1.col1.find():
print(x)

次回はオブジェクト型のドキュメントを追加していきます。

MongoDB(5) - ドキュメント作成編

今回はMongoDBのドキュメント追加に関する操作を行ってみます。

ドキュメントはRDBのレコードに相当します。

1件のドキュメント追加

ドキュメントを1件追加する場合は、insertOne関数を使います。

ドキュメントを追加するコレクションはcol1です。

コレクション(col1)は作成していなくても自動で作成されます。

(便利な反面、意図しないコレクションを作成してしまう可能性がありますので、気を付けてください。)

[Mongoシェル]

1
2
3
4
5
6
7
8
> db.col1.insertOne({name:"佐藤", age:10})
{
"acknowledged" : true,
"insertedId" : ObjectId("611b0f607466ff972f94ccc6")
}

> db.col1.find()
{ "_id" : ObjectId("611b0f607466ff972f94ccc6"), "name" : "佐藤", "age" : 10 }

複数のドキュメント追加

ドキュメントを複数追加する場合は、insertMany関数を使います。

insertMany関数には、配列データを渡します。

[Mongoシェル]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
> db.col1.insertMany([
{name:"鈴木", age:12},
{name:"高橋", age:15},
{name:"中村", age:19}
])
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("611b10127466ff972f94ccc7"),
ObjectId("611b10127466ff972f94ccc8"),
ObjectId("611b10127466ff972f94ccc9")
]
}

> db.col1.find()
{ "_id" : ObjectId("611b0f607466ff972f94ccc6"), "name" : "佐藤", "age" : 10 }
{ "_id" : ObjectId("611b10127466ff972f94ccc7"), "name" : "鈴木", "age" : 12 }
{ "_id" : ObjectId("611b10127466ff972f94ccc8"), "name" : "高橋", "age" : 15 }
{ "_id" : ObjectId("611b10127466ff972f94ccc9"), "name" : "中村", "age" : 19 }

Pythonで操作

上記の操作をPythonでまとめて行うと、次のようになります。

[ソースコード]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from pymongo import MongoClient

# MongoDB操作用のインスタンスを作成
client = MongoClient() # [IPとポートを指定する場合] MongoClient('10.200.243.203', 27017')

# データベースの取得
db1 = client.db1

# ドキュメント1件追加
data1 = {'name':'佐藤', 'age':10}
db1.col1.insert_one(data1)

# 全件表示
for x in db1.col1.find():
print(x)

# ドキュメント複数追加
data3 = [{'name':'鈴木', 'age':12},
{'name':'高橋', 'age':15},
{'name':'中村', 'age':19}]
db1.col1.insert_many(data3)

# 全件表示
for x in db1.col1.find():
print(x)

次回はいろいろなデータ型や配列データをドキュメントとして追加していきます。

MongoDB(4) - Cappedコレクション編

今回はMongoDBのCappedコレクションを作成します。

Cappedコレクションは、古いデータを自動で削除してくれるコレクションです。

ログ用のコレクションとしてよく使われます。

Cappedコレクション作成

Cappedコレクションの作成を行います。コレクション名はcap1とします。

Cappedコレクションを作成するときは、createCollectionコマンド実行時にオプションを指定します。

[Mongoシェル]

1
2
3
4
5
> use db1
switched to db db1

> db.createCollection("cap1", {capped:true, size:1024000, max:3})
{ "ok" : 1 }

上記ではサイズの上限(size)が1MB、ドキュメント数の上限(max)が3のCappedコレクションを作成しています。(サイズの単位はbyteとなります)

どちらかの上限に達したときに、古いデータが自動で削除されます。


作成したCappedコレクションの統計情報を確認してみます。

[Mongoシェル]

1
2
3
4
5
6
7
8
9
10
11
12
> db.cap1.stats()
{
"ns" : "db1.cap1",
"size" : 0,
"count" : 0,
"storageSize" : 4096,
"freeStorageSize" : 0,
"capped" : true,
"max" : 3,
"maxSize" : 1024000,
(略)
}

対応するオプションは下記の通りで、正しく設定されていることが確認できます。

  • capped
    Cappedコレクションであるかどうか。
  • max
    ドキュメント数の上限値。
  • maxSize
    コレクションの最大サイズ。

Cappedコレクションの注意点

Cappedコレクションを使用する場合は、下記の3点に注意する必要があります。

  • サイズの上限を変更できない。
    もしサイズを変更したい場合は、新しいCappedコレクションを作成して、データを移行するという手順が必要になります。
  • データの削除・更新ができない。
    データが自動的に削除されていくことが前提にあるため、ドキュメントの削除・更新ができません。
  • シャーディングできない。
    Cappedコレクションをシャーディングすることはできません。
    (シャーディングとは、コレクションごとにデータを複数サーバ分散することができる機能です。)

Cappedコレクションの動作確認

ドキュメントの追加と検索の詳細操作は今後行う予定ですが、Cappedコレクションの動作を確認するためにすこし実行してみます。

[Mongoシェル]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# ドキュメントを3件追加
> db.cap1.insertOne({age:1})
{
"acknowledged" : true,
"insertedId" : ObjectId("611a3bcdbc6e53b3d72248e0")
}
> db.cap1.insertOne({age:2})
{
"acknowledged" : true,
"insertedId" : ObjectId("611a3bd4bc6e53b3d72248e1")
}
> db.cap1.insertOne({age:3})
{
"acknowledged" : true,
"insertedId" : ObjectId("611a3bd6bc6e53b3d72248e2")

# 全データを確認
> db.cap1.find()
{ "_id" : ObjectId("611a3bcdbc6e53b3d72248e0"), "age" : 1 }
{ "_id" : ObjectId("611a3bd4bc6e53b3d72248e1"), "age" : 2 }
{ "_id" : ObjectId("611a3bd6bc6e53b3d72248e2"), "age" : 3 }

# ドキュメントを1件追加
> db.cap1.insertOne({age:4})
{
"acknowledged" : true,
"insertedId" : ObjectId("611a3bf5bc6e53b3d72248e3")
}

# 全データを確認(古いデータが1件削除されていることが確認できる)
> db.cap1.find()
{ "_id" : ObjectId("611a3bd4bc6e53b3d72248e1"), "age" : 2 }
{ "_id" : ObjectId("611a3bd6bc6e53b3d72248e2"), "age" : 3 }
{ "_id" : ObjectId("611a3bf5bc6e53b3d72248e3"), "age" : 4 }

通常コレクションからCappedコレクションへの変更

通常のコレクションをCappedコレクションに変更することもできます。

cap2というコレクションをいったん作成し、それをCappedコレクションに変更してみます。

[Mongoシェル]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 通常コレクションを作成
> db.createCollection("cap2")
{ "ok" : 1 }

# 変更前のコレクションの統計情報を表示
> db.cap2.stats()
{
"ns" : "db1.cap2",
"size" : 0,
"count" : 0,
"storageSize" : 4096,
"freeStorageSize" : 0,
"capped" : false,
(略)
}

# 通常コレクションをCappedコレクションに変更
> db.runCommand({"convertToCapped":"cap2", size:1024, max:1})
{ "ok" : 1 }


# 変更後のコレクションの統計情報を表示
> db.cap2.stats()
{
"ns" : "db1.cap2",
"size" : 0,
"count" : 0,
"storageSize" : 4096,
"freeStorageSize" : 0,
"capped" : true,
"max" : 0,
"maxSize" : 1024,
(略)
}

上記では、サイズの上限が1024バイトでドキュメント数の上限が1のCappedコレクションに変換しています。

統計情報を見ると、cappedオプションがtrueになりサイズの上限(maxSize)が1024になっていることが確認できます。

ただし、ドキュメント数の上限値(max)が1になっていません。

調べたところCappedコレクションへの変更を行うときmaxオプション(ドキュメント数の上限値)は指定できるものの、コレクションに反映することができないという謎仕様があるとのことです。

Cappedコレクションの変更コマンドは使わずに、新規でCappedコレクションを作成しデータの移行をした方が安全かもしれません😅😅

MongoDB(3) - コレクション操作編

今回はMongoDBのコレクションに関する操作を行ってみます。

コレクションは、RDBのテーブルに相当します。

コレクション作成

コレクションの作成を行います。コレクション名はgroupとします。

DB(データベース名:db1)を選択してから操作を行います。

[Mongoシェル]

1
2
3
4
5
> use db1
switched to db db1

> db.createCollection("group")
{ "ok" : 1 }

コレクションの一覧表示

コレクションの一覧を表示します。

[Mongoシェル]

1
2
> show collections
group

さきほど作成したgroupというコレクションが存在することを確認できます。

コレクションの統計情報

コレクションの統計情報を表示します。

各種性能を計測したり、運用時にデータ量を確認する場合に便利です。

[Mongoシェル]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
> db.group.stats()
{
"ns" : "db1.group",
"size" : 0,
"count" : 0,
"storageSize" : 4096,
"freeStorageSize" : 0,
"capped" : false,
"wiredTiger" : {
"metadata" : {
"formatVersion" : 1
},
"creationString" : "access_pattern_hint=none,allocation_size=4KB,app_metadata=(formatVersion=1),assert=(commit_timestamp=none,durable_timestamp=none,read_timestamp=none,write_timestamp=off),block_allocation=best,block_compressor=snappy,cache_resident=false,checksum=on,colgroups=,collator=,columns=,dictionary=0,encryption=(keyid=,name=),exclusive=false,extractor=,format=btree,huffman_key=,huffman_value=,ignore_in_memory_cache_size=false,immutable=false,import=(enabled=false,file_metadata=,repair=false),internal_item_max=0,internal_key_max=0,internal_key_truncate=true,internal_page_max=4KB,key_format=q,key_gap=10,leaf_item_max=0,leaf_key_max=0,leaf_page_max=32KB,leaf_value_max=64MB,log=(enabled=true),lsm=(auto_throttle=true,bloom=true,bloom_bit_count=16,bloom_config=,bloom_hash_count=8,bloom_oldest=false,chunk_count_limit=0,chunk_max=5GB,chunk_size=10MB,merge_custom=(prefix=,start_generation=0,suffix=),merge_max=15,merge_min=0),memory_page_image_max=0,memory_page_max=10m,os_cache_dirty_max=0,os_cache_max=0,prefix_compression=false,prefix_compression_min=4,readonly=false,source=,split_deepen_min_child=0,split_deepen_per_child=0,split_pct=90,tiered_object=false,tiered_storage=(auth_token=,bucket=,bucket_prefix=,local_retention=300,name=,object_target_size=10M),type=file,value_format=u,verbose=[],write_timestamp_usage=none",
"type" : "file",
"uri" : "statistics:table:collection-7-156884005367683298",
"LSM" : {
"bloom filter false positives" : 0,
"bloom filter hits" : 0,
"bloom filter misses" : 0,
"bloom filter pages evicted from cache" : 0,
"bloom filter pages read into cache" : 0,
"bloom filters in the LSM tree" : 0,
"chunks in the LSM tree" : 0,
"highest merge generation in the LSM tree" : 0,
"queries that could have benefited from a Bloom filter that did not exist" : 0,
"sleep for LSM checkpoint throttle" : 0,
"sleep for LSM merge throttle" : 0,
"total size of bloom filters" : 0
},
"block-manager" : {
"allocations requiring file extension" : 0,
"blocks allocated" : 0,
"blocks freed" : 0,
"checkpoint size" : 0,
"file allocation unit size" : 4096,
"file bytes available for reuse" : 0,
"file magic number" : 120897,
"file major version number" : 1,
"file size in bytes" : 4096,
"minor version number" : 0
},
"btree" : {
"btree checkpoint generation" : 0,
"btree clean tree checkpoint expiration time" : 0,
"column-store fixed-size leaf pages" : 0,
"column-store internal pages" : 0,
"column-store variable-size RLE encoded values" : 0,
"column-store variable-size deleted values" : 0,
"column-store variable-size leaf pages" : 0,
"fixed-record size" : 0,
"maximum internal page key size" : 368,
"maximum internal page size" : 4096,
"maximum leaf page key size" : 2867,
"maximum leaf page size" : 32768,
"maximum leaf page value size" : 67108864,
"maximum tree depth" : 0,
"number of key/value pairs" : 0,
"overflow pages" : 0,
"pages rewritten by compaction" : 0,
"row-store empty values" : 0,
"row-store internal pages" : 0,
"row-store leaf pages" : 0
},
"cache" : {
"bytes currently in the cache" : 182,
"bytes dirty in the cache cumulative" : 0,
"bytes read into cache" : 0,
"bytes written from cache" : 0,
"checkpoint blocked page eviction" : 0,
"checkpoint of history store file blocked non-history store page eviction" : 0,
"data source pages selected for eviction unable to be evicted" : 0,
"eviction walk passes of a file" : 0,
"eviction walk target pages histogram - 0-9" : 0,
"eviction walk target pages histogram - 10-31" : 0,
"eviction walk target pages histogram - 128 and higher" : 0,
"eviction walk target pages histogram - 32-63" : 0,
"eviction walk target pages histogram - 64-128" : 0,
"eviction walk target pages reduced due to history store cache pressure" : 0,
"eviction walks abandoned" : 0,
"eviction walks gave up because they restarted their walk twice" : 0,
"eviction walks gave up because they saw too many pages and found no candidates" : 0,
"eviction walks gave up because they saw too many pages and found too few candidates" : 0,
"eviction walks reached end of tree" : 0,
"eviction walks restarted" : 0,
"eviction walks started from root of tree" : 0,
"eviction walks started from saved location in tree" : 0,
"hazard pointer blocked page eviction" : 0,
"history store table insert calls" : 0,
"history store table insert calls that returned restart" : 0,
"history store table out-of-order resolved updates that lose their durable timestamp" : 0,
"history store table out-of-order updates that were fixed up by reinserting with the fixed timestamp" : 0,
"history store table reads" : 0,
"history store table reads missed" : 0,
"history store table reads requiring squashed modifies" : 0,
"history store table truncation by rollback to stable to remove an unstable update" : 0,
"history store table truncation by rollback to stable to remove an update" : 0,
"history store table truncation to remove an update" : 0,
"history store table truncation to remove range of updates due to key being removed from the data page during reconciliation" : 0,
"history store table truncation to remove range of updates due to out-of-order timestamp update on data page" : 0,
"history store table writes requiring squashed modifies" : 0,
"in-memory page passed criteria to be split" : 0,
"in-memory page splits" : 0,
"internal pages evicted" : 0,
"internal pages split during eviction" : 0,
"leaf pages split during eviction" : 0,
"modified pages evicted" : 0,
"overflow pages read into cache" : 0,
"page split during eviction deepened the tree" : 0,
"page written requiring history store records" : 0,
"pages read into cache" : 0,
"pages read into cache after truncate" : 0,
"pages read into cache after truncate in prepare state" : 0,
"pages requested from the cache" : 0,
"pages seen by eviction walk" : 0,
"pages written from cache" : 0,
"pages written requiring in-memory restoration" : 0,
"tracked dirty bytes in the cache" : 0,
"unmodified pages evicted" : 0
},
"cache_walk" : {
"Average difference between current eviction generation when the page was last considered" : 0,
"Average on-disk page image size seen" : 0,
"Average time in cache for pages that have been visited by the eviction server" : 0,
"Average time in cache for pages that have not been visited by the eviction server" : 0,
"Clean pages currently in cache" : 0,
"Current eviction generation" : 0,
"Dirty pages currently in cache" : 0,
"Entries in the root page" : 0,
"Internal pages currently in cache" : 0,
"Leaf pages currently in cache" : 0,
"Maximum difference between current eviction generation when the page was last considered" : 0,
"Maximum page size seen" : 0,
"Minimum on-disk page image size seen" : 0,
"Number of pages never visited by eviction server" : 0,
"On-disk page image sizes smaller than a single allocation unit" : 0,
"Pages created in memory and never written" : 0,
"Pages currently queued for eviction" : 0,
"Pages that could not be queued for eviction" : 0,
"Refs skipped during cache traversal" : 0,
"Size of the root page" : 0,
"Total number of pages currently in cache" : 0
},
"checkpoint-cleanup" : {
"pages added for eviction" : 0,
"pages removed" : 0,
"pages skipped during tree walk" : 0,
"pages visited" : 0
},
"compression" : {
"compressed page maximum internal page size prior to compression" : 4096,
"compressed page maximum leaf page size prior to compression " : 131072,
"compressed pages read" : 0,
"compressed pages written" : 0,
"page written failed to compress" : 0,
"page written was too small to compress" : 0
},
"cursor" : {
"Total number of entries skipped by cursor next calls" : 0,
"Total number of entries skipped by cursor prev calls" : 0,
"Total number of entries skipped to position the history store cursor" : 0,
"Total number of pages skipped without reading by cursor next calls" : 0,
"Total number of pages skipped without reading by cursor prev calls" : 0,
"Total number of times a search near has exited due to prefix config" : 0,
"bulk loaded cursor insert calls" : 0,
"cache cursors reuse count" : 0,
"close calls that result in cache" : 1,
"create calls" : 1,
"cursor next calls that skip due to a globally visible history store tombstone" : 0,
"cursor next calls that skip greater than or equal to 100 entries" : 0,
"cursor next calls that skip less than 100 entries" : 1,
"cursor prev calls that skip due to a globally visible history store tombstone" : 0,
"cursor prev calls that skip greater than or equal to 100 entries" : 0,
"cursor prev calls that skip less than 100 entries" : 0,
"insert calls" : 0,
"insert key and value bytes" : 0,
"modify" : 0,
"modify key and value bytes affected" : 0,
"modify value bytes modified" : 0,
"next calls" : 1,
"open cursor count" : 0,
"operation restarted" : 0,
"prev calls" : 0,
"remove calls" : 0,
"remove key bytes removed" : 0,
"reserve calls" : 0,
"reset calls" : 2,
"search calls" : 0,
"search history store calls" : 0,
"search near calls" : 0,
"truncate calls" : 0,
"update calls" : 0,
"update key and value bytes" : 0,
"update value size change" : 0
},
"reconciliation" : {
"approximate byte size of timestamps in pages written" : 0,
"approximate byte size of transaction IDs in pages written" : 0,
"dictionary matches" : 0,
"fast-path pages deleted" : 0,
"internal page key bytes discarded using suffix compression" : 0,
"internal page multi-block writes" : 0,
"internal-page overflow keys" : 0,
"leaf page key bytes discarded using prefix compression" : 0,
"leaf page multi-block writes" : 0,
"leaf-page overflow keys" : 0,
"maximum blocks required for a page" : 0,
"overflow values written" : 0,
"page checksum matches" : 0,
"page reconciliation calls" : 0,
"page reconciliation calls for eviction" : 0,
"pages deleted" : 0,
"pages written including an aggregated newest start durable timestamp " : 0,
"pages written including an aggregated newest stop durable timestamp " : 0,
"pages written including an aggregated newest stop timestamp " : 0,
"pages written including an aggregated newest stop transaction ID" : 0,
"pages written including an aggregated newest transaction ID " : 0,
"pages written including an aggregated oldest start timestamp " : 0,
"pages written including an aggregated prepare" : 0,
"pages written including at least one prepare" : 0,
"pages written including at least one start durable timestamp" : 0,
"pages written including at least one start timestamp" : 0,
"pages written including at least one start transaction ID" : 0,
"pages written including at least one stop durable timestamp" : 0,
"pages written including at least one stop timestamp" : 0,
"pages written including at least one stop transaction ID" : 0,
"records written including a prepare" : 0,
"records written including a start durable timestamp" : 0,
"records written including a start timestamp" : 0,
"records written including a start transaction ID" : 0,
"records written including a stop durable timestamp" : 0,
"records written including a stop timestamp" : 0,
"records written including a stop transaction ID" : 0
},
"session" : {
"object compaction" : 0,
"tiered operations dequeued and processed" : 0,
"tiered operations scheduled" : 0,
"tiered storage local retention time (secs)" : 0,
"tiered storage object size" : 0
},
"transaction" : {
"race to read prepared update retry" : 0,
"rollback to stable history store records with stop timestamps older than newer records" : 0,
"rollback to stable inconsistent checkpoint" : 0,
"rollback to stable keys removed" : 0,
"rollback to stable keys restored" : 0,
"rollback to stable restored tombstones from history store" : 0,
"rollback to stable restored updates from history store" : 0,
"rollback to stable sweeping history store keys" : 0,
"rollback to stable updates removed from history store" : 0,
"transaction checkpoints due to obsolete pages" : 0,
"update conflicts" : 0
}
},
"nindexes" : 1,
"indexBuilds" : [ ],
"totalIndexSize" : 4096,
"totalSize" : 8192,
"indexSizes" : {
"_id_" : 4096
},
"scaleFactor" : 1,
"ok" : 1
}

かなり多めの統計情報が表示されますが、よく参照する情報は下記の通りです。

フィールド名説明
sizeメモリに展開されるデータの合計サイズ
countコレクションに入っているデータ件数
storageSizeストレージのサイズ(データ圧縮後のサイズ)
cappedCappedコレクションかどうか(true:Cappedコレクション)
nindexesインデックス数
totalIndexSizeインデックスのデータ量の合計
indexSizes各インデックスのデータ量

コレクションの削除

コレクションを削除します。

[Mongoシェル]

1
2
> db.group.drop()
true

これでコレクションが削除されました。

データ件数によりますが、コレクションの中のデータを全て削除したいときは、コレクションを削除してその後コレクションを再作成する方が早いです。

Pythonで操作

上記の操作をPythonでまとめて行うと、次のようになります。

[ソースコード]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pymongo import MongoClient

# MongoDB操作用のインスタンスを作成
client = MongoClient() # [IPとポートを指定する場合] MongoClient('10.200.243.203', 27017')

# データベースの取得(存在しない場合は作成)
db1 = client.db1

# コレクションの作成(ドキュメントが追加されるまで作成されない)
cl = db1.group

# コレクションの一覧作成
lst_cl = db1.list_collection_names()
print(lst_cl)

# コレクションの統計情報取得
cl_info = db1.command("collstats", "group")
print(cl_info)

# コレクションの削除
db1.drop_collection('group')

次回はコレクションのとして特別なCappedコレクションに関する操作を行います。

MongoDB(2) - データベース操作編

前回はMongoDBを使えるようにセッティングを行いました。

今回はMongoDBのデータベースに関する操作を行ってみます。

データベース作成

データベースの作成を行います。データベース名はdb1とします。

[Mongoシェル]

1
2
> use db1
switched to db db1

useコマンドは、データベースの選択を行います。

ただしデータベースを選択しただけでデータベースが作成されるわけではありません。

データベースを選択した後にコレクションの作成などを行って、はじめてデータベースが作成されます。

データベースの一覧表示

データベースの一覧を表示します。

[Mongoシェル]

1
2
3
4
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB

admin、config、local という3つのデータベースが存在することを確認できます。

データベースの統計情報

データベースの統計情報を表示します。

各種性能を計測したり、運用時にデータ量を確認する場合に便利です。

(useコマンドで選択されているデータベースの情報が表示されます。)

[Mongoシェル]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
> db.stats()
{
"db" : "db1",
"collections" : 0,
"views" : 0,
"objects" : 0,
"avgObjSize" : 0,
"dataSize" : 0,
"storageSize" : 0,
"totalSize" : 0,
"indexes" : 0,
"indexSize" : 0,
"scaleFactor" : 1,
"fileSize" : 0,
"fsUsedSize" : 0,
"fsTotalSize" : 0,
"ok" : 1
}

参照頻度の高い情報を下記の一覧にまとめます。

フィールド名説明
collectionsデータベースの中にあるコレクション数
dataSize圧縮される前のデータサイズ
storageSizeコレクションに割り当てられたスペースの合計サイズ
(データ圧縮されたあとのサイズ)
indexesインデックス数
indexSizeインデックスのデータ量の合計
fileSizeストレージに保存されるファイルのサイズ

データベースの削除

データベースを削除します。

[Mongoシェル]

1
2
> db.dropDatabase()
{ "ok" : 1 }

MongoDBでは簡単にデータベースを作成できるので、一時的なデータベースや不要になったデータベースは削除しておきましょう。

Pythonで操作

上記の操作をPythonでまとめて行うと、次のようになります。

[ソースコード]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pymongo import MongoClient

# MongoDB操作用のインスタンスを作成
client = MongoClient() # [IPとポートを指定する場合] MongoClient('10.200.243.203', 27017')

# データベースの取得(存在しない場合は作成)
db1 = client.db1

# データベースの一覧取得
lst_db = client.database_names()
print(lst_db)

# データベースの統計情報取得
db_info = db1.command("dbstats")
print(db_info)

# データベースの削除
client.drop_database('db1')

次回はコレクションに関する操作を行います。

MongoDB(1) - 準備編

今回からMongoDBに関する記事を書いていきます。

コンソールからの操作とその操作をPythonで行う場合の2種類でMongoDBの動作確認を行います。

(最近Python関連の記事を全く書いていないことに気づきました・・・😨😨)

MongoDBとは

MongoDBは、NoSQLの1つです。

NoSQLの中でもMongoDBはシェアがトップという調査結果があります。

MongoDBが選ばれる理由としては下記が挙げられます。

  • スキーマレスにより保守性が高い
  • 高パフォーマンス
  • RDBと似た操作により学習効率が高い
  • オープンソースのため無料
  • 簡単な設定でスケールアウト(負荷分散)が可能

MongoDBのインストール

下記サイトからMongoDBのインストーラをダウンロードし、MongoDBをインストールします。

各環境に合わせてインストールを行ってください。

MongoDB Community Server - https://www.mongodb.com/try/download/community

(Community Serverが無料版になります。)

コンソールの準備(Mongoシェル)

インストール先にbinフォルダ(ディレクトリ)があり、そこにパスを通しておくとコンソールからMongoシェルを実行することができます。

コンソールからmongoと入力すると、Mongoシェルが起動します。

[コンソール]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
>mongo
MongoDB shell version v5.0.2
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("958c42c1-e0fe-45ec-b53e-d1a0db49c950") }
MongoDB server version: 5.0.2
================
Warning: the "mongo" shell has been superseded by "mongosh",
which delivers improved usability and compatibility.The "mongo" shell has been deprecated and will be removed in
an upcoming release.
We recommend you begin using "mongosh".
For installation instructions, see
https://docs.mongodb.com/mongodb-shell/install/
================
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see
https://docs.mongodb.com/
Questions? Try the MongoDB Developer Community Forums
https://community.mongodb.com
---
The server generated these startup warnings when booting:
2021-08-14T09:24:46.540+09:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
---
---
Enable MongoDB's free cloud-based monitoring service, which will then receive and display
metrics about your deployment (disk utilization, CPU, operation statistics, etc).

The monitoring data will be available on a MongoDB website with a unique URL accessible to you
and anyone you share the URL with. MongoDB may use this information to make product
improvements and to suggest MongoDB products and deployment options to you.

To enable free monitoring, run the following command: db.enableFreeMonitoring()
To permanently disable this reminder, run the following command: db.disableFreeMonitoring()
---
>

上記のように表示されたら、成功です。

このMongoシェルから、MongoDBを操作することができます。

Python用の準備

PythonからMongoDBを操作するためにはpymongoライブラリを使用します。

pipコマンドでインストールします。

[コンソール]

1
2
3
4
5
6
>pip install pymongo
Collecting pymongo
Downloading pymongo-3.12.0-cp38-cp38-win_amd64.whl (397 kB)
|████████████████████████████████| 397 kB 6.8 MB/s
Installing collected packages: pymongo
Successfully installed pymongo-3.12.0

以上で、コンソールとPythonからMongoDBを利用する準備ができました。


次回から、MongoDBをいろいろと操作していきます。

Ethereum(52) - オーバーフロー⑦(uintの最大値チェック)

今回はuintの最大値に関する動作を確認していきます。

ソースコード

最大値のチェックを行うためのソースコードは下記の通りです。

[ソースコード]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
pragma solidity ^0.4.11;
contract MarketPlaceOverflow {
address public owner;
uint public stockQuantity;

modifier onlyOwner() {
require(msg.sender == owner);
_;
}

/// 追加在庫数を表示するイベント
event AddStock(uint _addedQuantity);

/// コンストラクタ
function MarketPlaceOverflow() {
owner = msg.sender;
stockQuantity = 0; // 最大値をチェックするため100を0に変更
}

/// 在庫の追加処理
function addStock(uint _addedQuantity) public onlyOwner {
// オーバーフローチェック
require(stockQuantity + _addedQuantity > stockQuantity);

AddStock(_addedQuantity);
stockQuantity += _addedQuantity;
}
}

17行目で初期の在庫数を100から0に変更しています。

これは在庫の追加数としてuintの最大値を設定できるかどうかをテストするためです。

デプロイ

上記ソースのデプロイを行います。

[デプロイ]


デプロイ後のコントラクトの状態を確認します。

[コントラクト状態]

初期の在庫数(Stock quantity)が0であることが確認できます。

在庫の追加(最大値)

Add Stcok関数を使って、uintの最大値を設定します。

uintの最大値は115792089237316195423570985008687907853269984665640564039457584007913129639935です。

[在庫数を追加]

追加後の在庫数を確認します。

[在庫数を確認]

問題なくuintの最大値が在庫数(Stock quantity)に設定されていることが分かります。

また画像一番下のイベント情報より正しい数値(uintの最大値)が引数として渡されていることも分かります。

在庫の追加(最大値+1)

次に、uintの最大値を超える数値を設定してみます。

[uintの最大値]+1の数値は115792089237316195423570985008687907853269984665640564039457584007913129639936になります。

[在庫数を追加]

[EXECUTE]ボタンを押すと、トランザクションを発行するための画面が表示されます。

ここでパスワードを入力し、[SEND TRANSACTION]ボタンを押したところ次のようなメッセージが表示されました。

[トランザクション実行画面]

どうやら256バイトを超える値は設定できないようです。

uint8の場合は、それを超える数値を設定できたので、データ型の制限ではなくSolidityの引数の制限だと思われます。(ただの推測です)

以上で、オーバーフローに関する動作確認とその対策に関する記事は終わりにします。

Ethereum(51) - オーバーフロー⑥(2回目の改善確認編)

前回修正したスマートコントラクトを使ってオーバーフローが解消されているかどうかを確認します。

デプロイ

デプロイを行います。

デプロイするのは前回改善したMarket Place Overflowです。

[デプロイ]


デプロイ後のコントラクトの状態を確認します。

[コントラクト状態]

在庫数(Stock quantity)が100であることが確認できます。

在庫の追加

Add Stcok関数を使って、(前回NGとなった)在庫数257の追加を行います。

[在庫数を追加]

追加後の在庫数を確認します。

[在庫数を確認]

前回はオーバーフローが発生したため在庫数が101となってしまいましたが、今回は問題なく357となりました。


念のためイベントをを確認し、正しい引数が渡されているかどうかを確認します。

[イベントの確認]

問題なく257が引数として渡されています。

まとめ

オーバーフローの対策として次の2点を改善しました。

  • 在庫数を追加するときに、追加後の在庫数が増えることを確認。
    (オーバーフローが発生すると追加後の在庫数が減ってしまうため)
  • 追加する在庫数と既存の在庫数のデータ型をuint8からuintに変更。
    (uint8の範囲を超える数値が引数として渡されると、意図しない数値に変換されてしまうため)

2つめの修正ですが、扱える数字が増えただけで根本的な解決にはなっていなような気がします。

指定したデータ型を超える数値を指定したら結局またオーバーフローが発生してしまうと考えられるからです。


次回はuintを超える数値を設定して動作確認を行ってみます。