airbnbのデータをMongoDBにインポートし、検索データをBrowserで表示する

# 概要

airbnbが公開しているデータをMongoDBにインポートして、そのデータをmongoシェルで検索します。その結果をBrowserを使って表示します。

# 実行環境

- Windows 10
- MongoDB 4.0.9

# airbnbデータのダウンロード

http://insideairbnb.com/get-the-data.html

今回は上記URLからシドニー(Sydney)の2019/3/7分のデータ

- `listings.csv.gz`
- `reviews.csv.gz`

をダウンロードします。東京(Tokyo)はエラーとなりダウンロードできませんでした。

# MongoDBにインポート

ダウンロードしたデータを解凍して、`mongoimport`ツールを使ってインポートします。

|ファイル名|データベース名|コレクション名|
|---------|------------|------------|
|listings.csv| test | listings|
|reviews.csv| test | reviews|

### CSVデータのインポート

```shell
mongoimport -d test -c listings --type csv --headerline listings.csv
mongoimport -d test -c reviews --type csv --headerline reviews.csv
```

# reviewsから日本語のコメントを検索して、listingsからデータを付加します

- reviewsのcommentsで日本語の判定にはひらがなの`てにをは`が入っているもとします。
    - comments:/[て|に|を|は]/ は正規表現で、`てにをは`のいずれかが含まれていれば対象になります。
    - その他のひらがなや`良かった`,`おすすめ`などを含めてもOKです。漢字を使うと中国語も対象になってしまいます。
- listingsから付加するフィールド
    - listing_url
    - price
    - latitude  (緯度)
    - longitude  (経度)


検索する前に`listings`にインデックスを作成します。

```javascript
db.listings.createIndex({id:1})
```

次のJavascriptを`find.js`として作成します

```javascript:find.js
var docs=[]
db.reviews.find({comments:/[て|に|を|は]/}).forEach(doc=>{
   listing = db.listings.findOne({id:doc.listing_id})
   if (listing == null) return;
   data = {id:doc.listing_id, price:listing.price, url:listing.listing_url}
   data.latitude = listing.latitude
   data.longitude = listing.longitude
   data.comments = doc.comments
   docs.push(data)
})
print("var airbnbdata =")
printjson(docs)
```

`print("var aribnbdata=")`はJavascriptの変数として定義するためです。 `_id`はデータに含めないようにします。`_id`は`ObjectId()`の関数で表されますが、BrowserのJavascriptでは定義されていないためエラーになるからです。そのほかには`ISODate`や`NumberLong`などがエラーになります。自分で関数を定義すればエラーになりません。

上記のJavascriptをmongoシェルを使って実行します。

```shell
mongo --quiet find.js
```
エラーが無いことを確認したら、実行結果を`comments.js`として保存します。

```shell
mongo --quiet find.js  > comments.js
```

# 検索データをBrowserで表示する

次のhtmlファイルを`airbnb.html`として作成し、ローカルファイルとしてBrowserで表示させます。 

`comments.js`を先に記述してください。`listings`の緯度経度を使ってGoogleMapで表示するようにしています。GoogleMapの表示にはhttp://www.shurey.com/html/googlemaps.html を参考にしました。囲みのCSSはhttps://saruwakakun.com/html-css/reference/box を参考にしました。

```html:airbnb.html
<html>
<head>
    <meta charset="UTF-8">
    <style type="text/css">
        .innerbox {
            width: 600px;
            padding: 0.5em 1em;
            margin: 2em 0;
            border: solid 2px #6091d3;
            white-space: pre-wrap;
        }

        .outerbox {
            width: 640px;
            padding: 0.5em 1em;
            margin: 2em 0;
            border: double 5px #4ec4d3
        }
    </style>
</head>
<body>
    <div id="airbnb" align="center"></div>
    <script src="comments.js"></script>
    <script>
        let htmldata = []
        airbnbdata.forEach(doc => {
            htmldata.push(`<div class="outerbox" align="left">
            <p>${doc.id}<br>price:${doc.price}</p><a href="${doc.url}" target="_blank">${doc.url}</a><br>
            <a href="http://maps.google.co.jp/maps?q=loc:${doc.latitude},${doc.longitude}&iwloc=J" target="_blank">
            google map</a><pre class="innerbox">${doc.comments}</pre></div>`)
        })
        document.getElementById("airbnb").innerHTML = htmldata.join('\n')
    </script>
</body>
</html>
```
### Browserイメージ

実データではありません。
![sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258007/1d34869b-b27a-8650-835d-25c49bad8cbb.png)

# 参照URL

- http://insideairbnb.com/get-the-data.html
- http://www.shurey.com/html/googlemaps.html
- https://saruwakakun.com/html-css/reference/box