Node.jsとwijmoとWebAPIでMongoDBへCRUDしてみる（2022）

MongoDBにCRUDするメモ。グリッドはwijmoを使用。
いろんなところで手間取った。。。

# 環境
* Windows 10 64bit
* Node.js（v18.0.0）
* MongoDB（v5.08）
* wijmo（トライアル版：5.20221.842）

# 事前準備
* wijmoのトライアル版を入手
* MongoDB Compassで、データベース「webtest」＆コレクション「tasklist」を作成しておく
* MongoDBであらかじめデータを登録しておく
　({name:"xxxx",type:"xxx",status:xx})
* Node.jsのプロジェクト用フォルダを作り、expressとmongodbをインストールする

# MongoDBの状態
![compass.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2670417/08d080f6-ad44-ea8f-0186-d68b7cdfd3b4.png)


# プロジェクトフォルダ構成
folder/
  ├ node_modules/  ←express関連とmongodb
  ├ wijmo/
  │　└ index.html
  │　└ lib
  │　　　├ wijmo.min.css
  │　　　├ wijmo.min.js
  │　　　└ wijmo.grid.min.js
  ├ app.js
  └ package.json

# 画面イメージ（クライアント）
![screen.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2670417/f8e2a1f4-8344-ab96-851f-16fed59c749b.png)
* データを追加、編集、削除したら「データ送信」を押す（サーバ側へ書き込み）
* データ削除は「backspace」か「delete」
* 「データ取得」でサーバから最新データを取得する（デバッグ用）


# サーバ側（app.js）
~~~javascript:app.js
const express = require("express");
const app = express();

const mongodb = require("mongodb");
const MongoClient = mongodb.MongoClient;
const client = new MongoClient("mongodb://127.0.0.1:27017");
const db = client.db('webtest');

app.use(express.json());
app.use(express.static("wijmo"));

var taskList = [];

// read
app.get("/api/v1/list", async(req,res)=>{
    await client.connect();
    taskList = await db.collection("tasklist").find().toArray();
    await client.close();
    res.json(taskList);
});

// create
app.post("/api/v1/add", async(req,res)=>{
    await client.connect();
    const data = {
        name:req.body.name,
        type:req.body.type,
        status:req.body.status,
    }
    await db.collection("tasklist").insertOne(data);
    await client.close();
    res.sendStatus(200);
});

// update
app.put("/api/v1/item/:id", async(req,res)=>{
    await client.connect();
    const id = {_id : new mongodb.ObjectId(req.params.id)};
    const data = {
        name:req.body.name,
        type:req.body.type,
        status:req.body.status,
    }
    await db.collection("tasklist").updateOne(id,{$set:data});
    await client.close();
    res.sendStatus(200);
});

// delete
app.delete("/api/v1/item/:id", async(req,res)=>{
    await client.connect();
    const id = {_id : new mongodb.ObjectId(req.params.id)};
    await db.collection("tasklist").deleteOne(id);
    await client.close();
    res.sendStatus(200);
});

app.listen(3000,()=>{
    console.log("Listening Start port = 3000");
})
~~~

# クライアント側（index.html）
~~~javascript:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<link  href="lib/wijmo.min.css" rel="stylesheet"/>
<script src="lib/wijmo.min.js"></script>
<script src="lib/wijmo.grid.min.js"></script>
</head>
<body>
<h1>ToDo List</h1>
<div>
<button onclick="getData()">データ取得</button>
<button onclick="sendData()">データ送信</button>
</div>
<div id="wiGrid"></div>
<script>
const cv = new wijmo.collections.CollectionView();
cv.trackChanges = true;
const flexGrid = new wijmo.grid.FlexGrid("#wiGrid",{
    allowAddNew:true,
    allowDelete:true,
    itemsSource: cv,
    autoGenerateColumns: false,
    columns:[
        {binding:"name",header:"タスク"},
        {binding:"type",header:"種別"},
        {binding:"status",header:"状態"},
    ],
});
getData();

async function getData(){
    const res = await fetch("./api/v1/list");
    cv.sourceCollection = await res.json();
}

async function sendData(){
    // POST
    for(var i=0; i<cv.itemsAdded.length; i++){
        await fetch("./api/v1/add", {
            method: "POST",
            headers:{"Content-Type":"application/json"},
            body: JSON.stringify(cv.itemsAdded[i]),
        });
    }
    // PUT
    for(var i=0; i<cv.itemsEdited.length; i++){
        console.log(cv.itemsEdited[i]);
        await fetch("./api/v1/item/" + cv.itemsEdited[i]._id, {
            method: "PUT",
            headers:{"Content-Type":"application/json"},
            body: JSON.stringify(cv.itemsEdited[i]),
        });
    }
    // delete
    for(var i=0; i<cv.itemsRemoved.length; i++){
        await fetch("./api/v1/item/" + cv.itemsRemoved[i]._id, {
            method: "DELETE",
        });
    }
    getData();
}
</script>
</body>
</html>
~~~

# メモ
* wijmoのCollectionViewの扱い方を理解するまでに時間がかかった
* POSTでbodyのデータがクライアント側に届かず、難儀した（headerつけたら届いた）