mongoimportでネストされたオブジェクトとしてインポートする

概要

mongoimportでネストされたオブジェクトとしてインポートするためのメモです。

前提条件

  • MongoDB v4.0.10

今回使用するデータは公式ドキュメントのサンプルセットの中から、Inside Airbnbのデータを使わせていただきました。

元々は勉強用コードで見つけた内容なのですぐに試したい環境が欲しい場合はここを参照してください。
(勉強用に色々と触っているので内容は変わると思います)

結論

下記のように.で区切るとネストされたオブジェクトが作成されます。

listingId.int32()
date.date(2006-01-02)
available.string()
price.value.string()
price.adjusted.string()
nights.minimum.int32()
nights.maximum.int32()

インポートしたデータの取得結果です。
ネストされていることがわかりやすいように整形しています。

{
  "_id" : ObjectId("5d3ba3182101bb0c912c29d1"),
  "listingId" : 1600758,
  "date" : ISODate("2019-06-28T00:00:00Z"),
  "available" : "f",
  "price" : {
    "value" : "$3,300.00",
    "adjusted" : "$3,300.00"
  },
  "nights" : {
    "minimum" : 2,
    "maximum" : 7
  }
}

詳細

今回はfieldFileオプションを使って取り込みむのでfieldFileを作成します。
中身は結論で書いた内容と同じです。
columnsHaveTypesオプションを使っているので()つきの部分は型になります。

listingId.int32()
date.date(2006-01-02)
available.string()
price.value.string()
price.adjusted.string()
nights.minimum.int32()
nights.maximum.int32()

次にデータを取ってきます。

$ curl http://data.insideairbnb.com/japan/kant%C5%8D/tokyo/2019-06-27/data/calendar.csv.gz -O
$ gunzip calendar.csv.gz

mongoimportでデータを取り込みます。
コマンドは下記のような感じになります。

mongoimport \
    --db ${DB名} \
    --username ${ユーザ名} \
    --password ${パスワード} \
    --host ${ホスト}:${ポート} \
    --collection ${コレクション名} \
    --type csv \
    --file ${ダウンロードしたデータのパス} \
    --columnsHaveTypes \
    --parseGrace skipRow \
    --fieldFile ${作成したfieldFileのパス}

CSVによるインポートなので--type csvを指定し、
型の指定も行なっているので--columnsHaveTypesとつけます。

CSVの一行目はタイトル行なのでスキップするために--parseGrace skipRowを指定します。
本当は読み取れない行をスキップするオプションなのですが、タイトル行をスキップするために使っています。

実際に自分のローカルで実行したコマンドは下記です。

mongoimport \
    --db single-db \
    --username test-user \
    --password test-password \
    --host 127.0.0.1:27017 \
    --collection calendar \
    --type csv \
    --file /tmp/mongo-data/calendar.csv \
    --columnsHaveTypes \
    --parseGrace skipRow \
    --fieldFile ./single-node/docker/mongodb/csv-fields/calendar.txt

mongodbにログインし、1件数取り出してみるとこんな感じです。

> db.calendar.find().limit(1)

{ "_id" : ObjectId("5d3ba3182101bb0c912c29d1"), "listingId" : 1600758, "date" : ISODate("2019-06-28T00:00:00Z"), "available" : "f", "price" : { "value" : "$3,300.00", "adjusted" : "$3,300.00" }, "nights" : { "minimum" : 2, "maximum" : 7 } }

まとめ

ドキュメントを探してみたのですがネストオブジェクトの方法が見つからなかったので試してみました。
JIRAのISSUEにネストオブジェクトがインポートされないバグがあがっているので、
.で区切った場合にネストされたオブジェクトして扱われるのは仕様っぽいですね。