MongoDBのUbuntuへのインストールとシェルとPythonで動作確認


MongoDBをUbuntuにインストールしてシェルとPython(PyMongoパッケージ)で簡単な動作確認をしました。インストール方法は[「Install MongoDB Community Edition on Ubuntu」](https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/)を、[「Getting Started」](https://docs.mongodb.com/manual/tutorial/getting-started/)を参照しています。

# 環境
|種類|バージョン|内容|
|:--|:--|:--|
|OS|Ubuntu18.04.01 LTS|仮想で動かしています|
|MongoDB|4.2.0|2019年9月に最新|
|Python|3.6.8|Pyenvで動かしています|

# 手順
## [1. インストール](https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/)
.debパッケージを使ってインストールします。

### [1.1. MongoDBの公開鍵インポート](https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/#import-the-public-key-used-by-the-package-management-system)
ターミナルからMongoDBの公開鍵をインポート。

```bash
wget -qO - https://www.mongodb.org/static/pgp/server-4.2.asc | sudo apt-key add -
```

### [1.2. MongoDBのリストファイル作成](https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/#create-a-list-file-for-mongodb)

```bash
echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.2 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.2.list
```

### [1.3. パッケージDBの再読込](https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/#reload-local-package-database)

```bash
sudo apt-get update
```

### [1.4. MongoDBインストール](https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/#install-the-mongodb-packages)

```bash
sudo apt-get install -y mongodb-org
```
## 2. MongoDB起動
### [2.1. MongoDB起動](https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/#start-mongodb)
[mongod](https://docs.mongodb.com/manual/reference/program/mongod/#bin.mongod)を起動

```bash
sudo service mongod start
```

### [2.2. ログファイルから起動確認](https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/#verify-that-mongodb-has-started-successfully)

```bash
sudo cat /var/log/mongodb/mongod.log
```

ログファイルを見て、起動できているかを確認します。起動できている場合はデフォルトポート27017でリクエストを待っている旨が最後に出力されます。

```bash
2019-09-09T17:09:45.872+0900 I NETWORK  [initandlisten] waiting for connections on port 27017
```

## [3. Mongo Shellで簡単に試す](https://docs.mongodb.com/manual/mongo/#the-mongo-shell)
[mongod](https://docs.mongodb.com/manual/reference/program/mongod/#bin.mongod)を起動した状態でmongo shellを試します。

### [3.1. Local MongoDBにデフォルトPortで接続](https://docs.mongodb.com/manual/mongo/#local-mongodb-instance-on-default-port)
デフォルトポート27017でLocalのMongoDBに接続します。

```bash
mongo
```
DBの表示をします。`test`はデフォルトデータベースの名前です。

```bash
$ db
test
```

DB変更。今回は未登録のDB`myNewDatabase`を指定し、DB登録と変更を同時を行う。

```bash
$ use myNewDatabase
switched to db myNewDatabase
```

`myNewDatabase`のテーブル`myCollenction`に対してインサート。

```bash
$ db.myCollection.insertOne( { x: 1 } );
{
	"acknowledged" : true,
	"insertedId" : ObjectId("5cb9166e0424b2e17c7ce5eb")
}
```

テーブルから値を取得するクエリ実行。

```bash
$ db.myCollection.find().pretty()
{ "_id" : ObjectId("5cb9166e0424b2e17c7ce5eb"), "x" : 1 }
```

### [4. mongo Shellを少し深く試す](https://docs.mongodb.com/manual/tutorial/getting-started/)
もう少しだけmongo Shellを深く試します。
`inventory`というDBを登録します。

```bash
$ use inventory
switched to db inventory
```

### [4.1. Insert](https://docs.mongodb.com/manual/tutorial/getting-started/#insert-documents)
複数行を一括でInsert。

```bash
$ db.inventory.insertMany([
   // MongoDB adds the _id field with an ObjectId if _id is not present
   { item: "journal", qty: 25, status: "A",
       size: { h: 14, w: 21, uom: "cm" }, tags: [ "blank", "red" ] },
   { item: "notebook", qty: 50, status: "A",
       size: { h: 8.5, w: 11, uom: "in" }, tags: [ "red", "blank" ] },
   { item: "paper", qty: 100, status: "D",
       size: { h: 8.5, w: 11, uom: "in" }, tags: [ "red", "blank", "plain" ] },
   { item: "planner", qty: 75, status: "D",
       size: { h: 22.85, w: 30, uom: "cm" }, tags: [ "blank", "red" ] },
   { item: "postcard", qty: 45, status: "A",
       size: { h: 10, w: 15.25, uom: "cm" }, tags: [ "blue" ] }
]);

{
	"acknowledged" : true,
	"insertedIds" : [
		ObjectId("5cb9184d0424b2e17c7ce5ec"),
		ObjectId("5cb9184d0424b2e17c7ce5ed"),
		ObjectId("5cb9184d0424b2e17c7ce5ee"),
		ObjectId("5cb9184d0424b2e17c7ce5ef"),
		ObjectId("5cb9184d0424b2e17c7ce5f0")
	]
}
```

### [4.2. クエリ](https://docs.mongodb.com/manual/tutorial/getting-started/#query-documents)
クエリ系。

#### [4.2.1. 全取得](https://docs.mongodb.com/manual/tutorial/getting-started/#select-all-documents)
検索条件なしで全取得。

```bash
$ db.inventory.find( {} )

{ "_id" : ObjectId("5cb9184d0424b2e17c7ce5ec"), "item" : "journal", "qty" : 25, "status" : "A", "size" : { "h" : 14, "w" : 21, "uom" : "cm" }, "tags" : [ "blank", "red" ] }
{ "_id" : ObjectId("5cb9184d0424b2e17c7ce5ed"), "item" : "notebook", "qty" : 50, "status" : "A", "size" : { "h" : 8.5, "w" : 11, "uom" : "in" }, "tags" : [ "red", "blank" ] }
{ "_id" : ObjectId("5cb9184d0424b2e17c7ce5ee"), "item" : "paper", "qty" : 100, "status" : "D", "size" : { "h" : 8.5, "w" : 11, "uom" : "in" }, "tags" : [ "red", "blank", "plain" ] }
{ "_id" : ObjectId("5cb9184d0424b2e17c7ce5ef"), "item" : "planner", "qty" : 75, "status" : "D", "size" : { "h" : 22.85, "w" : 30, "uom" : "cm" }, "tags" : [ "blank", "red" ] }
{ "_id" : ObjectId("5cb9184d0424b2e17c7ce5f0"), "item" : "postcard", "qty" : 45, "status" : "A", "size" : { "h" : 10, "w" : 15.25, "uom" : "cm" }, "tags" : [ "blue" ] }
```

#### 4.2.2. 条件つきで検索
検索条件ありで検索。

```bash
$ db.inventory.find( { status: "D" } )

{ "_id" : ObjectId("5cb9184d0424b2e17c7ce5ee"), "item" : "paper", "qty" : 100, "status" : "D", "size" : { "h" : 8.5, "w" : 11, "uom" : "in" }, "tags" : [ "red", "blank", "plain" ] }
{ "_id" : ObjectId("5cb9184d0424b2e17c7ce5ef"), "item" : "planner", "qty" : 75, "status" : "D", "size" : { "h" : 22.85, "w" : 30, "uom" : "cm" }, "tags" : [ "blank", "red" ] }
```

#### [4.2.3. 深い階層部分に対する完全一致検索](https://docs.mongodb.com/manual/tutorial/getting-started/#match-an-embedded-document)
深い階層部分に対して完全一致条件で検索。

```bash
$ db.inventory.find( { size: { h: 14, w: 21, uom: "cm" } } )

{ "_id" : ObjectId("5cb9184d0424b2e17c7ce5ec"), "item" : "journal", "qty" : 25, "status" : "A", "size" : { "h" : 14, "w" : 21, "uom" : "cm" }, "tags" : [ "blank", "red" ] }
```

#### [4.2.4. 深い階層部分に対する条件つき検索](https://docs.mongodb.com/manual/tutorial/getting-started/#match-a-field-in-an-embedded-document)
深い階層部分に対して通常の条件つき検索。

```bash
$ db.inventory.find( { "size.uom": "in" } )

{ "_id" : ObjectId("5cb9184d0424b2e17c7ce5ed"), "item" : "notebook", "qty" : 50, "status" : "A", "size" : { "h" : 8.5, "w" : 11, "uom" : "in" }, "tags" : [ "red", "blank" ] }
{ "_id" : ObjectId("5cb9184d0424b2e17c7ce5ee"), "item" : "paper", "qty" : 100, "status" : "D", "size" : { "h" : 8.5, "w" : 11, "uom" : "in" }, "tags" : [ "red", "blank", "plain" ] }
```

#### [4.2.5. 配列型深い階層部分に対する検索](https://docs.mongodb.com/manual/tutorial/getting-started/#match-an-element-in-an-array)

```bash
$ db.inventory.find( { tags: "red" } )

{ "_id" : ObjectId("5cb9184d0424b2e17c7ce5ec"), "item" : "journal", "qty" : 25, "status" : "A", "size" : { "h" : 14, "w" : 21, "uom" : "cm" }, "tags" : [ "blank", "red" ] }
{ "_id" : ObjectId("5cb9184d0424b2e17c7ce5ed"), "item" : "notebook", "qty" : 50, "status" : "A", "size" : { "h" : 8.5, "w" : 11, "uom" : "in" }, "tags" : [ "red", "blank" ] }
{ "_id" : ObjectId("5cb9184d0424b2e17c7ce5ee"), "item" : "paper", "qty" : 100, "status" : "D", "size" : { "h" : 8.5, "w" : 11, "uom" : "in" }, "tags" : [ "red", "blank", "plain" ] }
{ "_id" : ObjectId("5cb9184d0424b2e17c7ce5ef"), "item" : "planner", "qty" : 75, "status" : "D", "size" : { "h" : 22.85, "w" : 30, "uom" : "cm" }, "tags" : [ "blank", "red" ] }
```

#### [4.2.6. 配列型深い階層部分に対する完全一致検索](https://docs.mongodb.com/manual/tutorial/getting-started/#match-an-array-exactly)

```bash
$ db.inventory.find( { tags: ["red", "blank"] } )
{ "_id" : ObjectId("5cb9184d0424b2e17c7ce5ed"), "item" : "notebook", "qty" : 50, "status" : "A", "size" : { "h" : 8.5, "w" : 11, "uom" : "in" }, "tags" : [ "red", "blank" ] }
```

### 4.3. DB削除
今回登録して使ったDB`inventory`を削除します。
`db.dropDatabase`で削除し、`show dbs`でなくなっていることを確認します。

```bash
$ db.dropDatabase()
{ "dropped" : "inventory", "ok" : 1 }

$ show dbs
admin          0.000GB
config         0.000GB
local          0.000GB
myNewDatabase  0.000GB
```


### 4.4. シェル終了
シェルを終了します。

```bash
$ exit
```

## [5. Pythonラッパー PyMongo](https://api.mongodb.com/python/current/index.html)
### [5.1. インストール](https://api.mongodb.com/python/current/installation.html)
pipを使ってPythonラッパーの[PyMongo](https://api.mongodb.com/python/current/)をインストールします。python仮想環境の管理はvenvを使っています。Pythonバージョンと仮想環境管理は記事[「UbuntuにpyenvとvenvでPython開発環境構築」](https://qiita.com/FukuharaYohei/items/2820f7bda6678ce26ea7)を参照ください。
PyMongo3.9.0がインストールされました。

```bash
pip install pymongo
```

jupyterを使ってPyMongoを動かします。

```bash
jupyter lab
```

### 5.2. Jupyter上でPython実行
ここからJupyter上でPythonを実行していきます。
[「2.1. MongoDB起動」](#21-mongodb%E8%B5%B7%E5%8B%95)を事前にしています。

#### [5.2.1. MongoDBへ接続](https://api.mongodb.com/python/current/tutorial.html#making-a-connection-with-mongoclient)
ローカルのMongoDBにデフォルトポートで接続し、クライアントを作成します。

```python
from pymongo import MongoClient
client = MongoClient()
```
#### [5.2.2. DBの取得/作成](https://api.mongodb.com/python/current/tutorial.html#getting-a-database)
今回は`test_database`というDBを作成します。作成済の場合は、取得されるだけです。`db = client['test-database']`のような書き方もOK。

```python
db = client.test_database
```

コマンド`list_database_names`を使えば、どんなDBがあるかを確認できます。

```python
client.list_database_names()
```


#### [5.2.3. コレクションの取得](https://api.mongodb.com/python/current/tutorial.html#getting-a-collection)
コレクションを取得します。`collection = db['test-collection']`のような書き方もOK。

```python
collection = db.test_collection
```

#### [5.2.4. Insert](https://api.mongodb.com/python/current/tutorial.html#documents)
JSON形式でデータを準備して`insert_one`関数でInsert。

```python
import datetime
post = {"author": "Mike",
        "text": "My first blog post!",
        "tags": ["mongodb", "python", "pymongo"],
        "date": datetime.datetime.utcnow()}
posts = db.posts
post_id = posts.insert_one(post).inserted_id
```

[`find_one`関数](https://api.mongodb.com/python/current/api/pymongo/collection.html#pymongo.collection.Collection.find_one)を使って結果確認をします。

```python
import pprint
pprint.pprint(posts.find_one())
```

結果が出力されます。

```json
{'_id': ObjectId('5d7a4f7055f20912298f04d4'),
 'author': 'Mike',
 'date': datetime.datetime(2019, 9, 12, 13, 59, 11, 121000),
 'tags': ['mongodb', 'python', 'pymongo'],
 'text': 'My first blog post!'}
```

[`find_one`関数](https://api.mongodb.com/python/current/api/pymongo/collection.html#pymongo.collection.Collection.find_one)は、以下のように条件を追加することもできます。

```python
pprint.pprint(posts.find_one({"author": "Mike"}))
```

#### [5.2.5. Bulk Inserts(一括挿入)](https://api.mongodb.com/python/current/tutorial.html#bulk-inserts)
[`insert_many`関数](https://api.mongodb.com/python/current/api/pymongo/collection.html#pymongo.collection.Collection.insert_many)を使ってBulk Inserts(一括挿入します)

```python
new_posts = [{"author": "Mike",
               "text": "Another post!",
               "tags": ["bulk", "insert"],
               "date": datetime.datetime(2009, 11, 12, 11, 14)},
              {"author": "Eliot",
               "title": "MongoDB is fun",
               "text": "and pretty easy too!",
               "date": datetime.datetime(2009, 11, 10, 10, 45)}]
result = posts.insert_many(new_posts)
result.inserted_ids
```

#### [5.2.6. クエリと複数結果](https://api.mongodb.com/python/current/tutorial.html#querying-for-more-than-one-document)
[`find`関数](https://api.mongodb.com/python/current/api/pymongo/collection.html#pymongo.collection.Collection.find)を使うと[`Cursor`インスタンス](https://api.mongodb.com/python/current/api/pymongo/cursor.html#pymongo.cursor.Cursor)

全検索だとすべてを取得できますし、

```python
for post in posts.find():
    pprint.pprint(post)
```

条件を指定してももちろんOK。

```python
for post in posts.find({"author": "Mike"}):
    pprint.pprint(post)
```


#### [5.2.7. カウント](https://api.mongodb.com/python/current/tutorial.html#counting)
[`count_documents`関数](https://api.mongodb.com/python/current/api/pymongo/collection.html#pymongo.collection.Collection.count_documents)で結果をカウントします。

```python
# 条件指定なし
posts.count_documents({})

# 条件指定
posts.count_documents({"author": "Mike"})
```

#### [5.2.8. クエリ応用](https://api.mongodb.com/python/current/tutorial.html#range-queries)
少しクエリの応用です。ここでは条件演算子で`<=`を使い、結果をソートします。詳しくは[Operators](https://docs.mongodb.com/manual/reference/operator/)を参照ください。

```python
d = datetime.datetime(2009, 11, 12, 12)
for post in posts.find({"date": {"$lt": d}}).sort("author"):
    pprint.pprint(post)
```

#### [5.2.9. Indexing](https://api.mongodb.com/python/current/tutorial.html#indexing)
インデックスの追加です。ここではユニークインデックスを追加しています。

```python
from pymongo import ASCENDING
result = db.profiles.create_index([('user_id', ASCENDING)], unique=True)
sorted(list(db.profiles.index_information()))
```

## 6. MongoDB停止
ターミナル上からMongoDBの停止です。

```bash
sudo service mongod stop
```