RaspberryPI + MongoDBを使う

MongoDBは、NoSQLデータベースと言われるのものです。
リレーショナルデータベースは、複数のテーブルを関連づけ高度な処理が可能となりますが、NoSQLデータベースは、非構造なデータを保管することが得意である反面、テーブル間の関連づけを持たないため、一貫性を持たせたい場合は、使う側が意識する必要があります。
様々なデータを保管していくならNoSQLの方が使い勝手はいいでしょう。


環境説明

まず、必要なパッケージは導入や、最低限のセキュリティや使い方を
学びましょう。

環境について

本環境は、別記事で導入した状態でスタートしています。
RaspberryPiのUbuntu環境です。こちらを参考にいただければと思います。

$ sudo apt list |grep mongodb-org
mongodb-org/bionic 4.4.18 amd64

$ python3 -V
Python 3.11.6

$ pip3 -V
pip 23.2 from /usr/lib/python3/dist-packages/pip (python 3.11)

$ mongo
MongoDB shell version v4.4.18

あと、Python 仮想環境として、venvで「flask」という環境を作っています。

<home dir>
└── app 
    └── flask   ⭐️ python venv

MongoDBのユーザ作成

セキュリティ設定

MongoDBのパスワードは設定しておきましょう。
作成するユーザとして、「homeAdmin」を作っておきます。
データの追加・参照はこのユーザを使って進めます。

MongoDBユーザの作成

まず、mongoのコンソールを開きます。

$ mongo
MongoDB shell version v4.4.18

>

データベースを「admin」へ切り替え、ユーザを作成します。

$$
\begin{array}{|l|l|l|} \hline
user: & homeAdmin & 作成するユーザ名を指定\\ \hline
pwd: & passwordPrompt() & コマンド実行後にパスワード入力
\\ \hline
\end{array}
$$

> use admin
switched to db admin

> db.createUser(
{
user: "homeAdmin",
pwd: passwordPrompt(),
roles: [ { role: "userAdminAnyDatabase", db: "admin" }, "readWriteAnyDatabase" ]
}
)

MongoDBの設定

⭐️アカウントを作成しただけでは、認証機能は有効になりません。⭐️
コンフィグファイルの修正が必要です。
本環境では、コンフィグファイルの場所は、「/etc/mongod.conf」です。
わからない場合は「systemctl status mongod」 とかでも分かると思います。

$ systemctl status mongod
● mongod.service - MongoDB Database Server
     Loaded: loaded (/lib/systemd/system/mongod.service; enabled; preset: enabled)
     Active: active (running) since Mon 2024-03-11 13:10:44 JST; 19h ago
       Docs: https://docs.mongodb.org/manual
   Main PID: 3200 (mongod)
     Memory: 191.2M
        CPU: 16min 29.997s
     CGroup: /system.slice/mongod.service
             └─3200 /usr/bin/mongod --config /etc/mongod.conf ⭐️

Mar 11 13:10:44 raspi-01 systemd[1]: Started mongod.service - MongoDB Database Server.

「mongod.conf」ファイルを開き、「security」セクションのコメントアウト
外し、「authorization: enabled」を追加します。

$ sudo nano /etc/mongod.conf

---------
security:
  authorization: enabled
---------

編集が完了したら、データベースを再起動、起動していることを確認します。

$ sudo systemctl daemon-reload
$ sudo systemctl restart mongod
$ sudo systemctl status mongod

MongoDBへ接続する

設定が完了したら、MongoDBへ接続します。
-u homeAdmin」を付け、ユーザを指定してログインします。

$ mongo -u homeAdmin
MongoDB shell version v4.4.18
Enter password:

connecting to: ・・・
Implicit session: session { "id" : UUID("・・・") }
MongoDB server version: 4.4.18
> 

ユーザ情報の確認

ユーザは「admin」データベースに作成していますので、
use admin」でデータベースを切り替え、「show users」で表示します。

> use admin
switched to db admin

> show users
{
	"_id" : "admin.homeAdmin", 
	"userId" : UUID("・・・・"),
	"user" : "homeAdmin",  ⭐️
	"db" : "admin",
	"roles" : [
		{
			"role" : "userAdminAnyDatabase",  ⭐️
			"db" : "admin"
		},
	],
	"mechanisms" : [
		"SCRAM-SHA-1",
		"SCRAM-SHA-256"
	]
}

データを入れてみよう

データを入れないと何もできないので、データを投入します。
入れるデータは、Excelを使って作成していきます。

Excelでデータを作成する

Excelでデータを作成するのに意外と簡単な作成方法があります。

$$
\begin{array}{|l|l|l|} \hline
項目 & 内容 & 作成方法 \\ \hline
code & 連番 & フィルで作成 \\ \hline
name & 英字5文字 & RANDBETWEEN関数で作成 \\ \hline
price & 1-10000の範囲 & RANDBETWEEN関数で作成 \\ \hline
category  & 英字1文字 & RANDBETWEEN関数で作成 \\ \hline
\end{array}
$$

name
= CHAR(RANDBETWEEN(65,90))&CHAR(RANDBETWEEN(65,90))&・・3回
CHAR(RANDBETWEEN(65,90))

  ・RANDBETWEEN(65,90)でA-Zの文字コードをランダムに返します。
  ・CHARでコードを文字に変換します。

price
=RANDBETWEEN(1,10000)
  ・1〜10000の間でランダム
category
=
CHAR(RANDBETWEEN(65,70))
  ・nameと同じだが、文字をA-Fの5文字

作成したExcelデータを、CSVで保存します。
ヘッダ込みで120行作成しました。

テストデータ

PandasでCSV読み込み

作成したテストデータのCSVを一度pandasで読み込みます。
flask venv配下に「mongdb」を作成し、テストデータとmongo.py
保存しています。

./flask/mongodb/  ⭐️
    ├── mongo.py  ⭐️
    └── test.csv  ⭐️

Pymongoのインストール

本記事では、Pymongoを使っていきます。
仮想環境をActivationして進めてください。

$ source flask/bin/activate

 (flask) ~/app$ python3 -m pip install pymongo

mongo.pyの作成

コードを書いていきます。
1:import
 ・pandas , json , pymongoを読み込んでいます。
 ・MongoDBに入れる際は、JSON形式にしてあげる必要があります。
2:read_csv
 ・データフレームにCSVを読み込みます。CSVのフォーマット形式に注意して
 ください。
3:DB接続
 ・MongoDBの接続情報を定義し接続します。先ほど作成した情報です。
4:JSON変換
 ・mongoDBにデータを入れるにはJson形式に変換が必要です。
5:MongoDB Insert
 ・DB: testdb、Collection:testlistにデータを入れます。
  一括で入れるには、「insert_many」を使用します。

# 1:import
import pandas as pd
from pymongo import MongoClient
import json

# 2:pandasでCSVを読み込む
df = pd.read_csv('flask/mongodb/test.csv',encoding="utf-8")

# 3:MongoDB接続情報
target = 'localhost'
port = 27017
user = "homeAdmin"
passwd = "123Admin!"

# インスタンス作成
client = MongoClient(
    target, 
    port, 
    username = user, 
    password = passwd
    )

# 4:データフレームをjson形式に変換
records = json.loads(df.T.to_json()).values()

# 5:データ書き込み
# 以下の場所にデータを入れます。
#  DB: testdb
#  Collection:testlist
mycol = client.testdb.testlist

# 一括でデータを入れます。
mycol.insert_many(records)

# DBコネクションクローズ
client.close()

実行します。(print入れてなかったので何もなく完了します。)

(flask) app$ python3 flask/mongodb/mongo.py

データを見てみましょう

データベースの確認

登録したデータが、コレクションに入っているか見てみます。
・mongoDBに、ユーザを指定しログインします。
・show dbs で、データベースが作成されているか確認します。
・use testdb で、データベースを選択し、db.stats() で、「"collections" : 1,」コレクションが作成されていることを確認します。
・show collections で、コレクション名を確認します。

$ mongo -u homeAdmin
MongoDB shell version v4.4.18
Enter password: 
MongoDB server version: 4.4.18
 
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB
testdb  0.000GB

> use testdb
switched to db testdb

db.stats()
{
	"db" : "testdb",
	"collections" : 1,
	"views" : 0,
	"objects" : 119,
	"avgObjSize" : 75,
	"dataSize" : 8925,
	"storageSize" : 20480,
	"indexes" : 1,
	"indexSize" : 20480,
	"totalSize" : 40960,
	"scaleFactor" : 1,
	"fsUsedSize" : 6065352704,
	"fsTotalSize" : 30900740096,
	"ok" : 1
}

> show collections
testlist

データを出力する

読み込む場合は、find() で表示可能です。

> db.testlist.find()

{ "_id" : ObjectId("65efcc775dff9b65fc8141c3"), "code" : 1, "name" : "MCVKG", "price" : 3869, "category" : "F" }
{ "_id" : ObjectId("65efcc775dff9b65fc8141c4"), "code" : 2, "name" : "TLYJB", "price" : 5843, "category" : "C" }
{ "_id" : ObjectId("65efcc775dff9b65fc8141c5"), "code" : 3, "name" : "CQTWL", "price" : 2968, "category" : "E" }
{ "_id" : ObjectId("65efcc775dff9b65fc8141c6"), "code" : 4, "name" : "EWRTN", "price" : 4665, "category" : "C" }
{ "_id" : ObjectId("65efcc775dff9b65fc8141c7"), "code" : 5, "name" : "RWLIF", "price" : 7586, "category" : "A" }
{ "_id" : ObjectId("65efcc775dff9b65fc8141c8"), "code" : 6, "name" : "WJLFC", "price" : 3743, "category" : "C" }
{ "_id" : ObjectId("65efcc775dff9b65fc8141c9"), "code" : 7, "name" : "TSMUR", "price" : 2877, "category" : "F" }
(省略)

検索する

・find({ "code": 12  }) :上の行は、code:12を検索して表示しています。
・find({"category": "A"}):下の行は、category:Aを検索して表示しています。
きちんと動いている様ですね。

db.testlist.find({"code": 12})
{ "_id" : ObjectId("65efcc775dff9b65fc8141ce"), "code" : 12, "name" : "ROOCV", "price" : 5367, "category" : "C" }

> db.testlist.find({"category": "A"})
{ "_id" : ObjectId("65efcc775dff9b65fc8141c7"), "code" : 5, "name" : "RWLIF", "price" : 7586, "category" : "A" }
{ "_id" : ObjectId("65efcc775dff9b65fc8141cd"), "code" : 11, "name" : "KLTHY", "price" : 8441, "category" : "A" }
{ "_id" : ObjectId("65efcc775dff9b65fc8141d3"), "code" : 17, "name" : "YOGAI", "price" : 547, "category" : "A" }
{ "_id" : ObjectId("65efcc775dff9b65fc8141d5"), "code" : 19, "name" : "YEMTY", "price" : 4195, "category" : "A" }
{ "_id" : ObjectId("65efcc775dff9b65fc8141d8"), "code" : 22, "name" : "ADCXM", "price" : 4645, "category" : "A" }
{ "_id" : ObjectId("65efcc775dff9b65fc8141da"), "code" : 24, "name" : "WPZWK", "price" : 9601, "category" : "A" }
{ "_id" : ObjectId("65efcc775dff9b65fc8141e0"), "code" : 30, "name" : "RFCPL", "price" : 8509, "category" : "A" }
{ "_id" : ObjectId("65efcc775dff9b65fc8141eb"), "code" : 41, "name" : "LMEXV", "price" : 6289, "category" : "A" }
{ "_id" : ObjectId("65efcc775dff9b65fc8141ec"), "code" : 42, "name" : "LTJLT", "price" : 8780, "category" : "A" }
{ "_id" : ObjectId("65efcc775dff9b65fc8141fe"), "code" : 60, "name" : "AQXUQ", "price" : 4581, "category" : "A" }
{ "_id" : ObjectId("65efcc775dff9b65fc814206"), "code" : 68, "name" : "YPSGZ", "price" : 2020, "category" : "A" }
{ "_id" : ObjectId("65efcc775dff9b65fc81420a"), "code" : 72, "name" : "UXTPI", "price" : 3897, "category" : "A" }
{ "_id" : ObjectId("65efcc775dff9b65fc81420d"), "code" : 75, "name" : "QNLBO", "price" : 7117, "category" : "A" }
{ "_id" : ObjectId("65efcc775dff9b65fc814212"), "code" : 80, "name" : "YMLRR", "price" : 5055, "category" : "A" }
{ "_id" : ObjectId("65efcc775dff9b65fc814213"), "code" : 81, "name" : "ZBYOZ", "price" : 2207, "category" : "A" }
{ "_id" : ObjectId("65efcc775dff9b65fc814216"), "code" : 84, "name" : "QAZJT", "price" : 1038, "category" : "A" }
{ "_id" : ObjectId("65efcc775dff9b65fc814218"), "code" : 86, "name" : "JRLPC", "price" : 9224, "category" : "A" }
{ "_id" : ObjectId("65efcc775dff9b65fc81421c"), "code" : 90, "name" : "EVOOL", "price" : 6186, "category" : "A" }
{ "_id" : ObjectId("65efcc775dff9b65fc81421f"), "code" : 93, "name" : "XCXSV", "price" : 797, "category" : "A" }
{ "_id" : ObjectId("65efcc775dff9b65fc814221"), "code" : 95, "name" : "LXPGU", "price" : 6379, "category" : "A" }

pythonでデータを読み込んでみよう

やっとここまで辿り着きました。
pythonで今入れたデータを読み込んでみましょう。

read_mongo.py

データを読み込むための、pythonファイルを作成しました。

./flask/mongodb/  
    ├── mongo.py  
    ├── read_mongo.py  🌟
    └── test.csv  

基本的に、上部は先ほどの登録する時のコードと変わりません。
・.find()で全件を取得
・データフレームに変換
が変わっている点です。

# import
import pandas as pd
from pymongo import MongoClient
import json

# MongoDB接続情報
target = 'localhost'
port = 27017
user = "homeAdmin"
passwd = "123Admin!"

# インスタンス作成
client = MongoClient(
    target, 
    port, 
    username = user, 
    password = passwd
    )

# データ場所
# データの場所の指定。
#  DB: testdb
#  Collection:testlist
mycol = client.testdb.testlist

# 全件を取得します。
record = mycol.find()

# データフレームに変換します。
df = pd.DataFrame(record)

# 表示します。
print(df)
print(df.info())

実行します。
データを読み込み(119行)、データ欠損もない様です。

(flask) ~/app$ python3 ./flask/mongodb/read_mongo.py 

                          _id  code   name  price category
0    65efcc775dff9b65fc8141c3     1  MCVKG   3869        F
1    65efcc775dff9b65fc8141c4     2  TLYJB   5843        C
2    65efcc775dff9b65fc8141c5     3  CQTWL   2968        E
3    65efcc775dff9b65fc8141c6     4  EWRTN   4665        C
4    65efcc775dff9b65fc8141c7     5  RWLIF   7586        A
..                        ...   ...    ...    ...      ...
114  65efcc775dff9b65fc814235   115  ZCDHJ   2234        D
115  65efcc775dff9b65fc814236   116  QEOPX   5097        E
116  65efcc775dff9b65fc814237   117  RTRRB     20        E
117  65efcc775dff9b65fc814238   118  EZDIZ   4884        E
118  65efcc775dff9b65fc814239   119  MUTRS   9609        B

[119 rows x 5 columns]

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 119 entries, 0 to 118
Data columns (total 5 columns):
 #   Column    Non-Null Count  Dtype 
---  ------    --------------  ----- 
 0   _id       119 non-null    object
 1   code      119 non-null    int64 
 2   name      119 non-null    object
 3   price     119 non-null    int64 
 4   category  119 non-null    object
dtypes: int64(2), object(3)
memory usage: 4.8+ KB
None

Queryを追加してみましょう。
先ほどのコードにqueryを追加し、find(query)に変更しました。

mycol = client.testdb.testlist

# query 
query = ({"code" : 12})

# 全件を取得します。
record = mycol.find(query)

# データフレームに変換します。
df = pd.DataFrame(record)

「code :12」だけが読み込めてますね。
pandasでフィルタしてもいいですが、DB側できちんと処理できていますね。

(flask) ~/app$ python3 ./flask/mongodb/read_mongo.py 

                        _id  code   name  price category
0  65efcc775dff9b65fc8141ce    12  ROOCV   5367        C

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1 entries, 0 to 0
Data columns (total 5 columns):
 #   Column    Non-Null Count  Dtype 
---  ------    --------------  ----- 
 0   _id       1 non-null      object
 1   code      1 non-null      int64 
 2   name      1 non-null      object
 3   price     1 non-null      int64 
 4   category  1 non-null      object
dtypes: int64(2), object(3)
memory usage: 172.0+ bytes
None

お疲れ様でした。MongoDBでデータを扱える様になりました。
pythonとmongoを行ったり来たりしていますが、queryを書く際は、
mongoで検索結果を確認しながらの作業になるため、mongoでの操作も
記載しました。

ここから下は、データベースの削除、起動エラー、read_csvの文字コードなどを
書いています。基本的に調べたら分かることですが、わからない場合にご参考まで。

ここから先は

7,096字

¥ 100

この記事が気に入ったらサポートをしてみませんか?