英文:
How can I modify the resulting query in Mongoose without affecting the actual document?
问题
状态(截至2020年5月6日): 已解决,请查看下面找到的答案。
我希望尽管我们正经历全球危机,一切都好。我目前正在进行一个学校网站项目,需要渲染我分配的特定功能。我正在使用Mongoose与Express,并使用Handlebars进行模板化。请查看下面附上的模型架构和解释。
collegeModel - 集合 A
var collegeSchema = new Schema({
	shortName: {type: String},	// 我打算同步查询它在集合 B 中的出现
	longName: {type: String},
	logo: {type: String},
	contactUs: {
		telNum: {type: String},
		faxNum: {type: String},
		email: {type: String}
	},
	aboutUs: {type: Array},
	visionMission: {type: String},
	coreValues: {type: String},
	goals: {type: String},
	founderBio: {type: String},
	philosophy: {type: String},
	icon: {type: String}
});
professorModel - 集合 B
var professorSchema = new Schema({
	profNumber: {type: Int32},
	college: {type: String},	// 与 shortName 进行比较的值
	gender: {type: String},
	profName: {type: String},
	profCourse: {type: String}
});
伪代码 - 要实现的期望逻辑
app.get('/testCount', function(req, res) {
	collegeModel.find({}).lean().exec(function(err, collegeRes) {
		var collegeObject = [];
		collegeRes.forEach(function(document) {
			professorModel.countDocuments({college: document.shortName}, function(err2, professorCount) {
				document.count = professorCount;
				collegeObject.push(document);	// 进行 console.log(collegeObject) 会返回空对象 []
			});
		});
	});
});
我不知道我做错了什么,我知道 document.count 存在,因为每次我执行 console.log(document.count) 时都会返回一个值,但当它被推送时变成了 []。希望你能帮助我实现我的目标。谢谢!
英文:
Status (as of 5/6/2020): Solved, see the identified answer below.
I hope all is well despite the global crisis we are experiencing right now. I am currently doing a school web project and need to render a specific feature assigned to me. I am using Mongoose with Express, and Handlebars for templating. Please see the attached model schema and explanation below.
collegeModel - Collection A
var collegeSchema = new Schema({
	shortName: {type: String},	//value that I intend to synchronously query its occurrence with Collection B
	longName: {type: String},
	logo: {type: String},
	contactUs:{
		telNum: {type: String},
		faxNum: {type: String},
		email: {type: String}
	},
	aboutUs: {type: Array},
	visionMission: {type: String},
	coreValues: {type: String},
	goals: {type: String},
	founderBio: {type: String},
	philosophy: {type: String},
	icon: {type: String}
});
professorModel - Collection B
var professorSchema = new Schema({
	profNumber: {type: Int32},
	college: {type: String},	//value to be compared with shortName
	gender: {type: String},
	profName: {type: String},
	profCourse: {type: String}
});
Pseudocode - Desired logic to be achieved
app.get('/testCount', function(req,res) {
	collegeModel.find({}).lean().exec(function(err,collegeRes){
		var collegeObject = [];
		collegeRes.forEach(function(document){
			professorModel.countDocuments({college:document.shortName}, function(err2,professorCount){
				document.count = professorCount;
				collegeObject.push(document);	//doing a console.log(collegeObject) would return empty objects [].
			});
		});
	});
});
I don't know what I'm doing wrong and I know document.count exists since it returns a value everytime I do console.log(document.count) but when it's pushed it becomes []. Hope you can help me achieve my goal. Thanks!
答案1
得分: 1
你的查询是异步解析的,你必须找到一种方法来等待它们全部完成,以确保你拥有所需的所有数据。
解决这个问题的一种方式是使用 async/await(Node.js >= 7.6.0)
app.get('/testCount', async function(req, res) { // 注意 async 关键字
  const collegeRes = await collegeModel.find({}).lean().exec() // .exec() 返回一个 Promise,所以你可以用 `await` 等待它。
  const resultPromises = collegeRes.map(async college => { // 箭头函数在这个上下文中相当于普通函数
    const professorCount = await professorModel.countDocuments({ college: college.shortName })
    college.count = professorCount
    return college
  })
  const collegeObject = await Promise.all(resultPromises)
  console.log(collegeObject)
})
稍微更可读的方式是使用 Promise.map 来自 bluebird 或者你也可以使用其他的 Promise 实用库。
const collegeObject = await Promise.map(collegeRes, college => {
  const professorCount = await professorModel.countDocuments({ college: college.shortName })
  college.count = professorCount
  return college
})
console.log(collegeObject)
英文:
Your queries resolve asynchronously, you have to find a way to wait for all of them to complete to make sure you have all the data you need.
One way to solve this is using async/await (Node.js >= 7.6.0)
app.get('/testCount', async function(req, res) { // note the async keyword
  const collegeRes = await collegeModel.find({}).lean().exec() // .exec() returns a Promise, so you can `await` it.
  const resultPromises = collegeRes.map(async college => { // arrow function is equivalent to function in this context
    const professorCount = await professorModel.countDocuments({ college: college.shortName })
    college.count = professorCount
    return college
  })
  const collegeObject = await Promise.all(resultPromises)
  console.log(collegeObject)
})
A bit more readable would be using Promise.map from bluebird or you can also use other promise utility library
  const collegeObject = await Promise.map(collegeRes, college => {
    const professorCount = await professorModel.countDocuments({ college: college.shortName })
    college.count = professorCount
    return college
  })
  console.log(collegeObject)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论