- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我设置了 newrelic 以更好地了解我的应用存在哪些瓶颈,但我发现了一个我似乎无法弄清楚的问题。
我的大部分延迟是由 mongoDB user.fineOne
引起的,但主要问题是我似乎无法找到代码中发生的位置。
在下图中,您可以看到调用我的 API 的 get/all/proposal
端点的跟踪详细信息。它首先是 14 个方法调用,它们是我 server.js 中的中间件,然后是 Middleware: Authenticate,其中包含 MongoDB Users findOne,这就是延迟所在。
获取/全部/提案的代码:
app.get('/all/proposals',isLoggedIn,function(req, res) {
Proposal.find().sort({proposalNo: -1}).limit(5).exec(function(err,proposal){
if(err){
console.log(err);
}else{
console.log("All Proposals " + proposal);
res.json(proposal);
}
});
});
现在我看不到我在 get/all/proposals
上在 MongoDB 上运行 User.findOne 调用。最初我以为是 isLoggedIn
中间件,我在其中检查用户是否在 session 中(Passport.js),但正如您所见,isLoggedIn Middleware
只需要 0.0222(毫秒)。
同样的问题出现在多个 API 端点上,即 get/caseStudy
并且它总是 user.findOne
下面的另一个示例:
谁能帮我解决这个问题。如果您需要更多详细信息,请告诉我,我猜您会的。
更新:Server.js 代码
// set up ======================================================================
require('newrelic');
var express = require('express');
var app = express(); // create our app w/ express
var server = require('http').createServer(app);
var mongoose = require('mongoose'); // mongoose for mongodb
var port = process.env.PORT || 8080; // set the port
var database = require('./config/db'); // load the database config
var morgan = require('morgan'); // log requests to the console (express4)
var bodyParser = require('body-parser'); // pull information from HTML POST (express4)
var methodOverride = require('method-override'); // simulate DELETE and PUT (express4)
var passport = require('passport');
var flash = require('connect-flash');
var session = require('express-session');
var cookieParser = require('cookie-parser');
var compression = require('compression');
var nodemailer = require('nodemailer');
var busboy = require("connect-busboy");
// configuration ===============================================================
mongoose.connect(database.url); // connect to mongoDB database on modulus.io
require('./config/passport')(passport);
app.use(express.static(__dirname + '/public'));
app.use(express.static(__dirname + '/views')); // set the static files location /public/img will be /img for users
app.use(busboy());
app.use(compression()); //use compression
app.use(morgan('dev')); // log every request to the console
app.use(bodyParser.urlencoded({'extended': true})); // parse application/x-www-form-urlencoded
app.use(bodyParser.json()); // parse application/json
app.use(bodyParser.json({ type: 'application/vnd.api+json' })); // parse application/vnd.api+json as json
app.use(methodOverride());
app.use(cookieParser()); // read cookies (needed for auth)
app.set('view engine', 'ejs'); // set up ejs for templating
// required for passport
app.use(session({ secret: '', resave: false, saveUninitialized: false })); // session secret
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
app.use(flash()); // use connect-flash for flash messages stored in session
// routes ======================================================================
require('./routes/index.js')(app, passport); // load our routes and pass in our app and fully configured passport
//require('./routes/knowledgeBase/index.js')(app, passport);
require('./routes/bios/index.js')(app, passport);
// listen (start app with node server.js) ======================================
app.listen(port);
console.log("App listening on port " + port);
更新 2:Passport.js
// config/passport.js
// load all the things we need
var LocalStrategy = require('passport-local').Strategy;
var crypto = require("crypto");
var api_key = '';
var domain = '';
var mailgun = require('mailgun-js')({apiKey: api_key, domain: domain});
// load up the user model
var User = require('../app/models/user');
// expose this function to our app using module.exports
module.exports = function(passport) {
// =========================================================================
// passport session setup ==================================================
// =========================================================================
// required for persistent login sessions
// passport needs ability to serialize and unserialize users out of session
// used to serialize the user for the session
passport.serializeUser(function(user, done) {
done(null, user.id);
});
// used to deserialize the user
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
// =========================================================================
// LOCAL SIGNUP ============================================================
// =========================================================================
// we are using named strategies since we have one for login and one for signup
// by default, if there was no name, it would just be called 'local'
passport.use('local-signup', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
firstNameField: 'firstName',
lastNameField: 'lastName',
usernameField: 'email',
passwordField: 'password',
jobTitleField: 'jobTitle',
startDateField: 'startDate',
passReqToCallback: true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) {
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
User.findOne({
'email': email
}, function(err, user) {
// if there are any errors, return the error
if (err)
return done(err);
// check to see if theres already a user with that email
if (user) {
return done(null, false, {
message: 'That email is already taken.'
});
}
else {
var token = crypto.randomBytes().toString();
// if there is no user with that email
// create the user
var newUser = new User();
// set the user's local credentials
newUser.firstName = req.body.firstName;
newUser.lastName = req.body.lastName;
newUser.email = email;
newUser.password = newUser.generateHash(password); // use the generateHash function in our user model
newUser.jobTitle = req.body.jobTitle;
newUser.startDate = req.body.startDate;
newUser.birthday = req.body.birthday;
newUser.region = req.body.region;
newUser.sector = req.body.sector;
newUser.accountConfirmationToken = token;
newUser.accountConfirmationTokenExpires = Date.now() + 3600000;
newUser.accountVerified = 'false';
// save the user
newUser.save(function(err) {
if (err)
throw err;
else {
return done(null, newUser);
}
});
}
});
}));
// =========================================================================
// LOCAL LOGIN =============================================================
// =========================================================================
// we are using named strategies since we have one for login and one for signup
// by default, if there was no name, it would just be called 'local'
passport.use('local-login', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) { // callback with email and password from our form
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
User.findOne({ 'email' : email }, function(err, user) {
// if there are any errors, return the error before anything else
if (err)
return done(err);
// if no user is found, return the message
if (!user)
return done(null, false, req.flash('loginMessage', 'No user found.')); // req.flash is the way to set flashdata using connect-flash
// if the user is found but the password is wrong
if (!user.validPassword(password))
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.')); // create the loginMessage and save it to session as flashdata
if(user.accountVerified == 'false')
return done(null, false, req.flash('loginMessage', 'Looks like you have not verified your account after registeration.'));
else
user.lastLogin = Date.now();
user.save(function(err) {
if (err)
throw err;
else {
// all is well, return successful user
return done(null, user);
}
});
});
}));
};
更新 3:isLoggedIn
函数
// route middleware to make sure a user is logged in
function isLoggedIn(req, res, next) {
// if user is authenticated in the session, carry on
if (req.isAuthenticated())
return next();
// if they aren't redirect them to the home page
res.redirect('/');
}
更新 4:获取提案的步骤
第 1 步:首先加载提案页面
app.get('/proposals',isLoggedIn,function(req, res) {
res.render('proposals.ejs', {
user : req.user // get the user out of session and pass to template
});
});
第 2 步:提案页面有一个 angular.js Controller /工厂,它在页面加载时调用以下函数来获取数据。
// =========================================================================
// FUNCTIONS TO BE RUN WHEN THE PAGE FIRST LOADS TO POPULATE FRONT-END =====
// =========================================================================
$scope.intialize = function() {
$scope.getAllSectors();
$scope.getLatestProposals();
}
// ===============================
// GET LATEST *5* PROPOSALS =====
// ===============================
factory.getLatestProposals = function() {
return $http.get('/all/proposals')
.then(function(response) {
//promise is fulfilled
deferred.resolve(response.data);
console.log("readched the filtered project service!");
//promise is returned
// return deferred.promise;
return response.data;
}, function(response) {
deferred.reject(response);
//promise is returned
return deferred.promise;
});
};
第 3 步:/all/proposals
路由被调用
// =======================
// GET All Proposals =====
// =======================
app.get('/all/proposals',isLoggedIn,function(req, res) {
Proposal.find().sort({proposalNo: -1}).limit(5).exec(function(err,proposal){
if(err){
console.log(err);
}else{
console.log("All Proposals " + proposal);
res.json(proposal);
}
});
});
最佳答案
查看您提供的代码后,您的性能日志中显示的 .findOne()
似乎是搜索用户并对其进行身份验证时执行的代码。
因此,性能瓶颈似乎出现在以下 2 个查询之一中:
/*
* LOCAL LOGIN
*/
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
User.findOne({ 'email' : email }, function(err, user) {
...
/*
* LOCAL SIGNUP
*/
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
User.findOne({
'email': email
...
我发现在您的两个护照本地策略中,您都在针对 email
字段进行搜索,因此您可以通过在该字段上创建索引来提高性能。
要尝试进一步优化 LOCAL LOGIN
findOne 查询,您可以尝试在 email
字段中为 users
集合添加索引,如果您还没有:
// This index will optimize queries that search against the {email} field
db.users.createIndex({ email: 1});
更新 #1
我找到了一个相关的 Stack Overflow topic这可能是您的性能问题的答案 - 您应该在 express.js
配置中更新以下行:
app.use(session({ secret: '', resave: false, saveUninitialized: false }));
到
app.use(session({ secret: '', resave: true, saveUninitialized: true }));
我还设法在 Express JS 文档中找到了有关 resave
和 saveUninitialized
属性的这些注释:
Forces a session that is "uninitialized" to be saved to the store. A session is uninitialized when it is new but not modified. Choosing false is useful for implementing login sessions, reducing server storage usage, or complying with laws that require permission before setting a cookie. Choosing false will also help with race conditions where a client makes multiple parallel requests without a session.
The default value is true, but using the default has been deprecated, as the default will change in the future. Please research into this setting and choose what is appropriate to your use-case.
Note if you are using Session in conjunction with PassportJS, Passport will add an empty Passport object to the session for use after a user is authenticated, which will be treated as a modification to the session, causing it to be saved. This has been fixed in PassportJS 0.3.0
Forces the session to be saved back to the session store, even if the session was never modified during the request. Depending on your store this may be necessary, but it can also create race conditions where a client makes two parallel requests to your server and changes made to the session in one request may get overwritten when the other request ends, even if it made no changes (this behavior also depends on what store you're using).
The default value is true, but using the default has been deprecated, as the default will change in the future. Please research into this setting and choose what is appropriate to your use-case. Typically, you'll want false.
How do I know if this is necessary for my store? The best way to know is to check with your store if it implements the touch method. If it does, then you can safely set resave: false. If it does not implement the touch method and your store sets an expiration date on stored sessions, then you likely need resave: true.
关于javascript - MongoDB 使用未知的 findOne 方法导致大延迟 - New Relic,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39992976/
我有一个 html 格式的表单: 我需要得到 JavaScript在value input 字段执行,但只能通过表单的 submit .原因是页面是一个模板所以我不控制它(不能有
我管理的论坛是托管软件,因此我无法访问源代码,我只能向页面添加 JavaScript 来实现我需要完成的任务。 我正在尝试用超链接替换所有页面上某些文本关键字的第一个实例。我还根据国家/地区代码对这些
我正在使用 JS 打开新页面并将 HTML 代码写入其中,但是当我尝试使用 document.write() 在新页面中编写 JS 时功能不起作用。显然,一旦看到 ,主 JS 就会关闭。用于即将打开的
提问不是为了解决问题,提问是为了更好地理解系统 专家!我知道每当你将 javascript 代码输入 javascript 引擎时,它会立即由 javascript 引擎执行。由于没有看过Engi
我在一个文件夹中有两个 javascript 文件。我想将一个变量的 javascript 文件传递到另一个。我应该使用什么程序? 最佳答案 window.postMessage用于跨文档消息。使
我有一个练习,我需要输入两个输入并检查它们是否都等于一个。 如果是 console.log 正则 console.log false 我试过这样的事情: function isPositive(fir
我正在做一个Web应用程序,计划允许其他网站(客户端)在其页面上嵌入以下javascript: 我的网络应用程序位于 http://example.org 。 我不能假设客户端网站的页面有 JQue
目前我正在使用三个外部 JS 文件。 我喜欢将所有三个 JS 文件合而为一。 尽一切可能。我创建 aio.js 并在 aio.js 中 src="https://code.jquery.com/
我有例如像这样的数组: var myArray = []; var item1 = { start: '08:00', end: '09:30' } var item2 = {
所以我正在制作一个 Chrome 扩展,它使用我制作的一些 TamperMonkey 脚本。我想要一个“主”javascript 文件,您可以在其中包含并执行其他脚本。我很擅长使用以下行将其他 jav
我有 A、B html 和 A、B javascript 文件。 并且,如何将 A JavaScript 中使用的全局变量直接移动到 B JavaScript 中? 示例 JavaScript) va
我需要将以下整个代码放入名为 activate.js 的 JavaScript 中。你能告诉我怎么做吗? var int = new int({ seconds: 30, mark
我已经为我的 .net Web 应用程序创建了母版页 EXAMPLE1.Master。他们的 I 将值存储在 JavaScript 变量中。我想在另一个 JS 文件中检索该变量。 示例1.大师:-
是否有任何库可以用来转换这样的代码: function () { var a = 1; } 像这样的代码: function () { var a = 1; } 在我的浏览器中。因为我在 Gi
我收到语法缺失 ) 错误 $(document).ready(function changeText() { var p = document.getElementById('bidp
我正在制作进度条。它有一个标签。我想调整某个脚本完成的标签。在找到可能的解决方案的一些答案后,我想出了以下脚本。第一个启动并按预期工作。然而,第二个却没有。它出什么问题了?代码如下: HTML:
这里有一个很简单的问题,我简单的头脑无法回答:为什么我在外部库中加载时,下面的匿名和onload函数没有运行?我错过了一些非常非常基本的东西。 Library.js 只有一行:console.log(
我知道 javascript 是一种客户端语言,但如果实际代码中嵌入的 javascript 代码以某种方式与在控制台上运行的代码不同,我会尝试找到答案。让我用一个例子来解释它: 我想创建一个像 Mi
我如何将这个内联 javascript 更改为 Unobtrusive JavaScript? 谢谢! 感谢您的回答,但它不起作用。我的代码是: PHP js文件 document.getElem
我正在寻找将简单的 JavaScript 对象“转储”到动态生成的 JavaScript 源代码中的最优雅的方法。 目的:假设我们有 node.js 服务器生成 HTML。我们在服务器端有一个对象x。
我是一名优秀的程序员,十分优秀!