Tea*_*ter 5 mongoose mongodb node.js async-await apollo-server
我是一名前端开发人员,试图在一个新的 Next 项目上扩展我的视野,第一次学习 Node、Mongo 和 GraphQL 的服务器端。Apollo 对我来说是最简单的入门方式,因为我已经在以前的项目中使用了客户端 Apollo。
我一直在关注官方文档,在那里我了解了apollo-datasource-mongodb(这似乎是将我的 Apollo Server 直接插入本地 Mongo 数据库的最佳方式。不幸的是,似乎没有这个包的任何示例存储库行动让我作弊,所以我一直糊涂。
我通过 mongo 在本地运行mongod,我可以find()通过 mongo shell执行成功的查询,所以我知道数据库本身状况良好并且包含近600,000 条记录(我正在处理一个相当大的数据集)。
我还可以访问 Apollo Playground,localhost:4000所以我知道服务器正在正确启动并连接到数据库(我已经设法解决了适当的架构提示/错误)。
这是我在 Playground 中使用的查询:
{
item(id: 22298006) {
title
}
}
Run Code Online (Sandbox Code Playgroud)
这就是我要回复的内容:
{
"errors": [
{
"message": "Topology is closed, please connect",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"item"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"name": "MongoError",
"stacktrace": [
"MongoError: Topology is closed, please connect",
...
]
}
}
}
],
"data": {
"item": null
}
}
Run Code Online (Sandbox Code Playgroud)
我在下面附上了我的服务器文件。我怀疑这可能是某种超时错误,比如梳理所有 600k 条记录以找到具有我提供的 ID 的记录需要很长时间?当我useUnifiedTopology: true从 MongoClient 定义中删除时,我收到一个不同的错误:
UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
Run Code Online (Sandbox Code Playgroud)
但我没有使用异步或承诺自己。我在想什么——我应该这样做吗?在等待返回时,我能否以某种方式阻止该过程findOneById()(如果这确实是问题所在)?
顺便说一句,我已经看到至少一个示例代码库,其中 MongoClient 在自身中包含一个 Server 声明(也来自'mongodb'npm 包)。实现类似的东西可以避免我mongod每次想要处理我的项目时都必须阻塞终端窗口吗?
非常感谢您的参与!如果我能做到这一点,我肯定会在 Medium 上写一篇完整的文章,或者为其他希望将 MongoClient 与 ApolloServer 配对以获得快速简便的 API 的人铺平道路。
索引.js
const { MongoClient } = require('mongodb');
const assert = require('assert');
const { ApolloServer, gql } = require('apollo-server');
const { MongoDataSource } = require('apollo-datasource-mongodb');
const client = new MongoClient('mongodb://localhost:27017/projectdb', { useNewUrlParser: true, useUnifiedTopology: true }, (err) => {
err && console.log(err);
});
client.connect((err) => {
assert.equal(null, err);
client.close();
});
const db = client.db();
class Items extends MongoDataSource {
getItem(id) {
return this.findOneById(id);
}
}
const typeDefs = gql`
type Item {
id: Int!
title: String!
}
type Query {
item(id: Int!): Item
}
`;
const resolvers = {
Query: {
item: (_, { id }, { dataSources }) => dataSources.items.getItem(id),
}
}
const server = new ApolloServer({
typeDefs,
resolvers,
dataSources: () => ({
items: new Items(db.collection('items')),
}),
});
server.listen().then(({ url }) => {
console.log(`Server ready at ${ url }`);
});
Run Code Online (Sandbox Code Playgroud)
感谢 GitHub 在apollo-datasource-mongodb上的“Used By”下拉菜单,我能够欺骗其他一些存储库,这就是我最终得到的结果(注释中标记了更改):
const { MongoClient } = require('mongodb');
const assert = require('assert');
const { ApolloServer, gql } = require('apollo-server');
const { MongoDataSource } = require('apollo-datasource-mongodb');
// Isolated these for prominence and reuse
const dbURL = 'mongodb://localhost:27017';
const dbName = 'projectdb';
// Made each function async/await
// Swapped the datasource's findOneById() for the collection itself & standard Mongo functions
class Items extends MongoDataSource {
async getItem(id) {
return await this.collection.findOne({id: id});
}
}
const typeDefs = gql`
type Item {
id: Int!
title: String!
}
type Query {
item(id: Int!): Item
}
`;
// Made each query async/await
const resolvers = {
Query: {
item: async (_, { id }, { dataSources }) => {
return await dataSources.items.getItem(id);
},
}
}
// Move the ApolloServer constructor to its own function that takes the db
const init = (db) = {
return new ApolloServer({
typeDefs,
resolvers,
dataSources: () => ({
items: new Items(db.collection('items')),
}),
});
}
// Use .connect() instead of new MongoClient
// Pass the new db to the init function defined above once it's been defined
// Call server.listen() from within MongoClient
MongoClient.connect(dbURL, { useNewUrlParser: true, useUnifiedTopology: true }, (err, client) => {
assert.equal(null, err);
const db = client.db(dbName);
console.log(`Mongo database ${ dbName } at ${ dbURL }`);
const server = init(db);
server.listen().then(({ url }) => {
console.log(`Server ready at ${ url }`);
});
});
Run Code Online (Sandbox Code Playgroud)
通过这些更改,位于 localhost:4000 的 Apollo Playground 运行得非常好!现在要解决我在查询时在客户端应用程序中遇到的 400 错误...