最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Unsure of how to approach Data Access ObjectLayer in an ExpressMongoDB Application - Stack Overflow

programmeradmin5浏览0评论

I have an Express application running with MongoDB. I want to separate out my database access from the server level. However, to get the result of a database call I can only seem to do one of two things:

Pass Res as an argument

//server.js
...
var dbApi = require('../data/db-api.js');
...
app.get('/api/user', dbApi.getUsers(function (data) {
  res.send(data);
}));
...

//db-api.js
...
getUsers: function (callback) {
  MongoClient.connect(url, function (err, db) {
  if (err) {
    throw err;
  }

  db.collection(collections.Users)
    .find({})
    .toArray(function (error, documents) {
      db.close();
      callback(documents);
    });
  });
}
...

Assume Express req/res paradigm in db-api.js

//server.js
...
var dbApi = require('../data/db-api.js');
...
app.get('/api/user', dbApi.getUsers);
...

//db-api.js
...
getUsers: function (req, res) {
  MongoClient.connect(url, function (err, db) {
  if (err) {
    throw err;
  }

  db.collection(collections.Users)
    .find({})
    .toArray(function (error, documents) {
      db.close();
      res.send(documents);
    });
  });
}
...

However, I feel both of these approaches add implicit dependencies I would prefer to avoid. I would prefer to call dbApi independently in server.js such that it returns a result set I can manipulate before returning, i.e.:

//server.js
...
var dbApi = require('../data/db-api.js');
...
app.get('/api/user', function (req, res) {
  var result = dbApi.getUsers();
  //do stuff with result as necessary
  res.send(result);
});
...

//db-api.js
getUsers: function () {
  MongoClient.connect(url, function (err, db) {
  if (err) {
    throw err;
  }

  db.collection(collections.Users)
    .find({})
    .toArray(function (error, documents) {
      db.close();
      return documents;
    });
  });
}

But this last one doesn't seem to want to work, as the documents aren't returned to the server level (result is undefined). I know this is because I'm trying to do something synchronously that is inherently asynchronous.

So, I suppose, what I'm looking for is any advice on best practices regarding app architecture as it pertains to separating out the data access layer.

I have an Express application running with MongoDB. I want to separate out my database access from the server level. However, to get the result of a database call I can only seem to do one of two things:

Pass Res as an argument

//server.js
...
var dbApi = require('../data/db-api.js');
...
app.get('/api/user', dbApi.getUsers(function (data) {
  res.send(data);
}));
...

//db-api.js
...
getUsers: function (callback) {
  MongoClient.connect(url, function (err, db) {
  if (err) {
    throw err;
  }

  db.collection(collections.Users)
    .find({})
    .toArray(function (error, documents) {
      db.close();
      callback(documents);
    });
  });
}
...

Assume Express req/res paradigm in db-api.js

//server.js
...
var dbApi = require('../data/db-api.js');
...
app.get('/api/user', dbApi.getUsers);
...

//db-api.js
...
getUsers: function (req, res) {
  MongoClient.connect(url, function (err, db) {
  if (err) {
    throw err;
  }

  db.collection(collections.Users)
    .find({})
    .toArray(function (error, documents) {
      db.close();
      res.send(documents);
    });
  });
}
...

However, I feel both of these approaches add implicit dependencies I would prefer to avoid. I would prefer to call dbApi independently in server.js such that it returns a result set I can manipulate before returning, i.e.:

//server.js
...
var dbApi = require('../data/db-api.js');
...
app.get('/api/user', function (req, res) {
  var result = dbApi.getUsers();
  //do stuff with result as necessary
  res.send(result);
});
...

//db-api.js
getUsers: function () {
  MongoClient.connect(url, function (err, db) {
  if (err) {
    throw err;
  }

  db.collection(collections.Users)
    .find({})
    .toArray(function (error, documents) {
      db.close();
      return documents;
    });
  });
}

But this last one doesn't seem to want to work, as the documents aren't returned to the server level (result is undefined). I know this is because I'm trying to do something synchronously that is inherently asynchronous.

So, I suppose, what I'm looking for is any advice on best practices regarding app architecture as it pertains to separating out the data access layer.

Share Improve this question asked Apr 14, 2015 at 1:26 Thomas PrestonThomas Preston 7171 gold badge8 silver badges20 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 2

Bit late to the party, but in my opinion the split should be that the Express handler deals with the HTTP request, and your other method deals with the database.

Expanding your original script and using callbacks:

//server.js
...
var dbApi = require('../data/db-api.js');
...
app.get('/api/user', (req, res) => {
  try {
    dbApi.getUsers((documents) => res.send(documents))
  } catch (error) {
    // or something along those lines
    res.status(500).send({ error: error.message });
  }
});
...

//db-api.js
...
getUsers: function () {
  MongoClient.connect(url, function (err, db) {
  if (err) {
    throw err;
  }

  db.collection(collections.Users)
    .find({})
    .toArray(function (error, documents) {
      db.close();
      if (error) {
        throw error;
      }
      return documents;
    });
  });
}

Sam H. is right as well, I'd promisify/async this so it bees more intuitive, the current versions of the Mongodb client on node will return a promise if you don't supply a callback:

//server.js
...
const dbApi = require('../data/db-api.js');
...
app.get('/api/user', async (req, res) => {
  try {
    const documents = await dbApi.getUsers();
    res.send(documents)
  } catch (error) {
    // or something along those lines
    res.status(500).send({ error: error.message });
  }
});
...

//db-api.js
...
getUsers: async function () {
  const db = await MongoClient.connect(url);
  const collection = await db.collection(collections.Users);
  const query = await collection.find({});
  const documents = await query.toArray();
  await db.close();
  return documents;
}

Or with Promises:

//server.js
...
const dbApi = require('../data/db-api.js');
...
app.get('/api/user', (req, res) => {
  dbApi.getUsers()
    .then(documents => res.send(documents))
    .catch(error => res.status(500).send({ error: error.message })
});
...

//db-api.js
...
getUsers: function () {
  return MongoClient.connect(url)
    .then(db => Promise.all([
      db,
      db.collection(collections.Users).find({}).toArray()
    ]))
    .then(([db, documents]) => Promise.all([documents, db.close()])
    .then(([documents]) => documents)
}

Well, you can use a promisified version of the mongo client, return the promise of that value, and use async/await. See, for example, this answer.

发布评论

评论列表(0)

  1. 暂无评论