質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.22%

node+Express+mongodb でDBから正常に値が取得できないことがあり困ってます

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,986

terry-0121

score 12

前提・実現したいこと

アマゾンのAPIを叩いて、
商品データをDBに格納するシステムを組んでおります。

いま実現したいのは、そのシステムの管理画面で、
DBにアクセスしてデータを取得してフォームを表示、
フォームでsubmitされたら
フォームのデータをPOSTで受け取ってDBに格納する処理です。

node+Express+mongodb、稼働サーバ環境はcentos、
開発環境はmac(elCapitan)です。

発生している問題・エラーメッセージ

DBから正常な値が取得できないことがあり、困っております。
以下に処理内容を記載します。

router.getが初回アクセス時の処理です。
DBから値をとってきてて、index.ejsを描画する処理です。
(プロミスはあまり意味がない状態になっていると思いますが、いろいろ試行錯誤した跡なのでできればスルーしていただけると)
router.post('/'・・・がPOST時の処理です。

フォームから受け取った値をdb_updateで更新して、
res.redirectでページを再表示させるように組んでいますが、
doc.saveした後に

AmazonDB.where().sort({'_id':'asc'}).exec(function(err,docs){
で再度DBにアクセスしてindexを描画する形をとっています。

ただ、saveの処理が完了していないうちに読みに行ってしまっているからだと思いますが、サーバ環境によっては正常な値がかえってきません。
(macでは動くけど、centosではダメだったり)

ページをリロードすると正常な値で表示されます。

これをうまく回避するにはどうしたらよいでしょうか。
お知恵を拝借できれば幸いです。

ソースコード

var express = require('express');
var router = express.Router();

var http = require('http');
var ejs = require('ejs');
var qs = require('querystring');
var server = http.createServer();

var Promise = require('bluebird');

const ITEM_MAX=40;

var mongoose = require('mongoose');
var AmazonSchema = new mongoose.Schema({
  asin: String,
  url: String,
  title: String,
  monitoring: String,
  starttime: String
});

var url = 'mongodb://localhost/ama';
var db = mongoose.connect(url);
var AmazonDB=db.model('ama',AmazonSchema);

// 初回アクセスの処理
router.get('/', function(req, res, next) {

  var get_DB = new Promise(function (resolve, reject) {
    AmazonDB.where().sort({'_id':'asc'}).exec(function(err,docs){
           if (err) {
               reject(error);
           } else {
               resolve(docs);
           }
       });
  });

  get_DB.then (function (docs) {
    res.render('index', { title: 'Express', json: docs });
  });
});

// postの処理 ---- ★1
router.post('/', function(req, res, next) {

    for (i=0; i<ITEM_MAX; i++){
      eval('var id=req.body.id'+i+';');
      eval('var asin=req.body.asin'+i+';');
      eval('var url=req.body.url'+i+';');
      eval('var title=req.body.title'+i+';');
      eval('var monitoring=req.body.monitoring'+i+';');
      eval('var starttime=req.body.starttime'+i+';');

      // タイトル、asin、urlの中身が空だった時はskip
      if(asin==null || url==null || title==null) {
        continue;
      }
      db_update(id,asin,url,title,monitoring,starttime);
    }
    res.redirect('/');
});

function db_update(id,asin,url,title,monitoring,starttime) {

  AmazonDB.findOne({
    '_id':id
  },function(err,doc){
    if (err){
      console.log(err);
    }
    doc.id=id;
    doc.asin=asin;
    doc.url=url;
    doc.title=title;
    doc.monitoring=monitoring;
    doc.starttime=starttime;

    doc.save(function(err) {
      if (err){
        console.log(err);
      }
    }).then();
  });
}

補足情報(言語/FW/ツール等のバージョンなど)

環境はcentos7、node v0.10.36、Express4.13.1、mongodb@2.1.4
mongoose@4.3.7です。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

回答 1

checkベストアンサー

0

単純にデータベースの更新処理を全て終えた後にビューの描画を行いたいということでしょうか?

それであれば、doc.saveの引数に渡している無名関数の最後で、
ビューの描画処理を行えば良いと思います。

ただし、全ての処理を終えた後にのみビューの描画処理が実行されるように、
何件処理が終わったかのカウントはとっておく必要があると思います。

以下のサイトの上から3つ目のコードが参考になると思います。(最初の1つ目と2つ目のコードは間違ったやり方を示すサンプルコードです)
http://mostafa-samir.github.io/async-iterative-patterns-pt1/

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/02/04 01:57

    回答をいただきありがとうございます。
    何件処理が終わったかのカウントを取ればいいということですね。
    ちょっとやってみます。
    できたらまたご連絡いたします。

    キャンセル

  • 2016/02/19 02:00

    うまくできました。ありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.22%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る