javascript - Mongoose post.save在heroku上失败,在本地主机上工作

标签 javascript node.js mongodb heroku mongoose

我试图简单地通过node,express,mongoose和heroku发布到我的MongoDB Atlas数据库。 postman POST请求,带有正文的Raw JSON:

{
    "title": "heroku post",
    "description": "post me plsssss"
}
可以在本地主机上使用此确切代码运行,但是当通过heroku上传时,try/catch块在post.save()上失败,因为响应是错误。
{
    "error": "there's an error",
    "message": {}
}
但是错误是空的,我不确定如何调试它。我在mongoose.set('debug', true);中放入了app.js,并修改了我的package.json:"start": "node app.js DEBUG=mquery",,但是这些并没有产生我所看到的额外输出。还有其他方法可以知道为什么post.save()引发错误,一些我没有使用的日志..以及如何查看这些日志?或者,如果您只知道问题出在哪里?
App.js
//use dotenv to store secret keys
require("dotenv").config();
const express = require('express');
const mongoose = require('mongoose');
const app = express();
const cors = require('cors');

//connect to DB
mongoose.connect("mongodb+srv://grushevskiy:intercom@cluster-rest.4luv0.mongodb.net/cluster-rest?retryWrites=true&w=majority", { useNewUrlParser: true, useUnifiedTopology: true, dbName: "cluster-rest" }, () => {
  console.log('connected to DB!')
})

mongoose.set('debug', true);

const db = mongoose.connection;

db.once('open', () => {
    console.log('connection opened')
});


//import routes for middleware
const postsRoute = require('./routes/posts');

//midleware routes
app.use('/posts', postsRoute)

//ROUTES
app.get('/', (req,res) => {
  res.send('we are on home')
})


//MIDDLEWARES
//cors
app.use(cors());
//decode url special characters
app.use(express.urlencoded({ extended: true }));
//parse json POSTs
app.use(express.json());


//How do we start listening to the server
app.listen( process.env.PORT || 3000);
posts.js
const express = require ('express')
const router = express.Router();
const Post = require('../models/Post')

//SUBMIT A POST
router.post('/', async (req,res) => {
  const post = new Post({
    title: req.body.title,
    description: req.body.description
  });

  console.log(post)

  try {
    const savedPost = await post.save();
    res.json(savedPost);
    console.log(savedPost)
  } catch (err) {
    res.json({ error: "there's an error", message: err, })
  }
})

module.exports = router;
Post.js模型
const mongoose = require('mongoose')
const PostSchema = mongoose.Schema({
  title: {
    type: String,
    required: true
  },
  description: {
    type: String,
    required: true
  },
  date: {
    type: Date,
    default: Date.now
  }
})
module.exports = mongoose.model('Post', PostSchema)
当我键入heroku logs --tail时,也没有错误,最初也就是“已连接到数据库!”消息来得有点晚..我想知道是否这是异步/等待的问题?我的package.json:
{
  "name": "22-npmexpressrestapi",
  "version": "1.0.0",
  "engines": {
    "node": "14.15.3",
    "npm": "6.14.9"
  },
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node app.js DEBUG=mquery",
    "start:dev": "node app.js"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "express": "^4.17.1",
    "nodemon": "^2.0.7"
  },
  "dependencies": {
    "dotenv": "^8.2.0",
    "express": "4.17.1",
    "cors": "^2.8.5",
    "mongoose": "^5.11.11"
  }
}

最佳答案

仔细阅读您的问题后,我有一些建议,我想您可能想尝试一下。首先,让我解释一下自己:
以我的经验,当学习使用Mongoose与MongoDB集群通信时,如何使用Node.js构建REST API时,其index.js文件的事件序列如下所示:

  • 执行使用环境变量建立与数据库集群的连接的函数。此函数仅运行一次,并使用为该应用程序设计的任何模型填充该应用程序要使用的de mongoose实例。
  • 通过要求适当的程序包,定义所需的中间件并调用已为此程序定义的所有路由来设置应用程序。
  • 应用程序整合了正常运行所需的一切之后,会调用app.listen(),并提供有效的端口,然后……瞧!您已使服务器运行。

  • 当应用程序和数据库非常简单时,这就像一个魅力。我使用这些相同的步骤构建了一些服务,并将它们投入生产,而没有注意到 Mongoose 和该应用程序之间的任何误传。但是,如果检查提供的App.js代码,您会发现情况有所不同:仅在设置应用程序,中间件和路由之后才连接到Mongo群集。如果其中任何一个依赖于 Mongoose 实例或要运行的模型,那么很有可能在Heroku的编译器到达需要路由连接到数据库的地步时,它根本没有实现该连接(这意味着没有运行mongoose.connect()部分)喷射。
    简单的解决方案
    我认为Heroku运行整个代码所花的时间比本地计算机要长一些。另外,如果您的本地版本正在连接到本地存储的MongoDB,则很有可能运行的速度比云服务中的运行速度要快得多。您的陈述

    the 'connected to DB!' message comes in a bit late


    给我希望可能是这种情况。如果是这样,那我想那感动mongoose.connect("mongodb+srv://xxxxx:xxxxx@cluster-rest.4luv0.mongodb.net/cluster-rest?retryWrites=true&w=majority", { useNewUrlParser: true, useUnifiedTopology: true, dbName: "cluster-rest" }, () => {console.log('connected to DB!')});调用Dotenv之后,将其移至App.js的第二行即可。您的 Mongoose 实例将进入已经与数据库和该模型关联的App。
    异步解决方案
    即使我以前写的解决了您的问题,我也想扩大解释,因为根据我的经验,该解决方案的版本也不正确。我在此答案开头公开的操作方式是可以的……只要您保持MongoDB集群和mongoose实例简单即可。不久前,我不得不实现一项涉及更为复杂的数据库模式的服务,同一应用程序使用了多个不同的数据库,并且其许多路由直接取决于这些数据库的模型。
    当我尝试使用之前描述的逻辑来解决这个问题时,涉及到人口稠密的数据库和mongoose实例中包含的多个模型,我意识到与构建连接到mongoose相比,Node花费更少的精力来构建App,其中间件和路由。并加载运行该应用所需的所有模型。这意味着在实际连接数据库之前,我收到了Server connected to PORT ****消息。这带来了麻烦。
    这使我意识到正确地做事的唯一方法是确保异步性,迫使App仅在将所有数据库和模型都加载到mongoose实例中后才运行,并将该实例提供给它。这样,我最终得到了一个类似于index.js的代码:

    const Dotenv = require("dotenv").config();
    const { connectMongoose } = require("./server/db/mongoose");
    const wrappedApp = require("./app");
    
    connectMongoose().then((mongoose) => {
      const App = wrappedApp(mongoose);
    
      App.listen(process.env.PORT, () => {
        console.log(
          `Hello, I'm your server and I'm working on port ${process.env.PORT}`
        );
      });
    });

    具有多个功能的文件,用于控制与我的数据库和模型的连接,称为mongoose.js。以正确的顺序实现所有连接的函数为:

    const connectMongoose = async (mongoose = require("mongoose")) => {
      try {
        // Close any previous connections
        await mongoose.disconnect();
    
        // Connect the Main database
        console.log(
          "--> Loading databases and models from MongoDB. Please don't use our server jet. <--"
        );
        mongoose = await connectMother(mongoose);
    
        // Connect all the client databases
        mongoose = await connectChildren(mongoose);
    
        console.log(
          "--> All databases and models loaded correctly. You can work now. <--"
        );
    
        return mongoose;
      } catch (e) {
        console.error(e);
      }
    };
    
    module.exports = { connectMongoose };

    这样,文件app.js返回了一个需要馈入 Mongoose 实例的函数,并设置了所有Express环境:

    module.exports = (Mongoose) => {
      const Express = require("express"); //Enrouting
      // Other required packages go here
    
      // EXPRESS SETTINGS
      const App = Express();
      App.set("port", process.env.PORT || 3000); //Use port from cloud server
    
      // All the middleware App needs
      App.use(Flash());
    
      // Routing: load your routes
      
      // Return fully formed App
      return App;
    };

    仅使用这种模式,我才能确保事件链是有意义的:
  • 连接所有数据库并加载其模型。
  • 只有在连接了最后一个数据库并加载了它的最后一个模型之后,才设置应用程序,其中间件和您的路由。
  • 使用App.listen()服务该应用程序。

  • 如果您的数据库不是很大,那么答案的第一部分可能会解决问题。但是了解整个故事总是很有用的。

    关于javascript - Mongoose post.save在heroku上失败,在本地主机上工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65675265/

    相关文章:

    ruby-on-rails - docker-compose mongo rails 连接失败

    javascript - NativeScript http.getJSON 和异步等待

    javascript - 如何在node.js中没有任何请求的情况下获取express-session值

    javascript - 不能在带有类验证器的父类的构造函数内部使用验证

    Node.js fs.readFile()

    ruby-on-rails - Rails & Mongoid 独特的结果

    javascript - 不使用循环的多个 MongoDB 查询?

    javascript - BackboneJS Youtube播放器仅渲染一次

    javascript - 如何在 JavaScript 中将小数转换为 32 位 int?

    javascript - 为什么我们设置node.fs : 'empty' in webpack?