【发布时间】:2019-05-21 22:02:27
【问题描述】:
我目前正在构建一个 Web 应用程序,但偶然发现了一个在过去 12 小时内无法解决的问题。
我正在研究一种基本的 get 方法,我试图检索员工正在工作的某些工作职位(即收银员、文员)(客户端工作得很好)。
WorkPosition 的猫鼬模型是这样的(models/work-position.js):
var mongoose = require('mongoose');
var User = require('./user');
var Schema = mongoose.Schema;
var schema = new Schema ({
workplace : {type: String, required: true},
type : {type: String, required: true},
status : {type: String, required: true},
color : {type: String, required: true},
employees: [{type: Schema.Types.ObjectId, ref:'User'}]
});
module.exports = mongoose.model('WorkPosition', schema);
我的get方法(routes/work-position.js):
var express = require('express');
var router = express.Router();
var jwt = require('jsonwebtoken');
var User = require('../models/user');
var mongoose = require('mongoose');
var WorkPosition = require('../models/work-position');
router.get('/:userId', function(req, res, next) {
const userId = req.params.userId;
WorkPosition.find({employees: {$elemMatch : {$eq: userId}}})
.exec(function(err, workPositions) {
if(err) {
return res.status(500).json({
title: 'an error has occurred',
error: err
});
}
console.log(userId);
console.log(workPositions);
res.status(200).json({
message: 'Success',
obj: workPositions
});
});
});
当我尝试使用 $elemMatch 方法时出现问题。上面的代码,当 WorkPosition.find 行改为
WorkPosition.find()
没有任何条件(
{employees: {$elemMatch : {$eq: userId}}}
) 在里面,我成功地检索到了我想要的 WorkPosition 文档。
但是,我只想检索 WorkPosition 中的“employees”字段与我从 req.params 收到的“userId”匹配的 WorkPosition 文档。因此,我搜索了mongodb/mongoose API (http://mongoosejs.com/docs/api.html#query_Query-elemMatch)
我在哪里找到了 $elemMatch 方法。
在 mongodb shell 中,当我这样做时
db.workpositions.find({"employees": { $elemMatch : {$eq: "596823efbac11d1978ba2ee9"}}})
其中“5968....”是userId,我可以成功查询WorkPosition文档。
通过这个命令,我可以验证我的逻辑是否正确,并且使用 mongodb native shell 命令可以得到我想要的文档。
但是,当我尝试将相同的逻辑转换为 Mongoose API 时:
WorkPosition.find().elemMatch('employees', {$eq : userId})
我得到一个空数组,并添加行
mongoose.set('debug', function (coll, method, query, doc) {
console.log(coll + " " + method + " " + JSON.stringify(query) + " " + JSON.stringify(doc));
});
在 /app.js 中,我可以看到 mongoose 查询转换为本地 mongodb 命令的内容:
workpositions find {"employees":{"$elemMatch":{"$eq":"596823efbac11d1978ba2ee9"}}} {"fields":{}}
。集合(工作位置)、方法(查找)、要查找的数组(员工)和所有内容都正确转换为本地 mongodb 命令,除了
"$eq"
。成功运行的 shell 命令和我代码中的 mongoose 命令之间的唯一区别是 '$eq' 周围的附加引号。
外壳:
db.workpositions.find({"employees": { $elemMatch : {$eq: "596823efbac11d1978ba2ee9"}}})
猫鼬:
db.workpositions.find({"employees": { $elemMatch : {"$eq": "596823efbac11d1978ba2ee9"}}})
我似乎找不到摆脱这些多余引号的方法(我认为这是问题的原因)。我尝试将本机命令与猫鼬一起使用:
mongoose.connection.db.workpositions.find(.....)
但这也会导致错误。
通过猫鼬使用 elemMatch 的正确方法是什么?谁能告诉我如何使用它?我尝试了所有我能想到的方法,但我似乎无法解决这个问题。
我正在考虑更改 WorkPosition.employees 字段,以便它包含实际用户(不仅是 userId),并且我可以使用与 Mongoose elemMatch API 完全匹配的其他信息进行解析。但是,我相信这会浪费大量的数据库空间,因为每个 WorkPosition 都必须携带一组用户。
要在用户和 WorkPositions 之间建立正确的关系,elemMatch 是我的项目中的一项要求。我将非常感谢任何帮助!
【问题讨论】:
-
由于您的员工字段只是一个 id 数组,您可以不只使用:WorkPosition.find({ employees: userId })
-
引用您的问题“在 mongodb shell 中,当我执行
db.workpositions.find({"employees": { $elemMatch : {$eq: "596823efbac11d1978ba2ee9"}}})时,我成功了(原文如此)”。所以有你的问题。如果您可以在“shell”中运行该查询,那么"employees"的内容实际上是“字符串”和 notObjectId值,这是您的架构所期望的。似乎您现有的数据有问题,您需要将这些条目修复为ObjectId值。 shell 查询应该失败,因为您没有转换值。 Mongoose 正在尝试转换值。 -
为了将来参考,请始终将
mongoose.set('debug',true)添加到您的程序中。这会记录从您的 mongoose 模型发出的所有查询,然后您应该能够看到像刚才说明的那样明显的差异。 -
首先,感谢@NeilLunn 指出我犯的小但重大的错误。我的文档和架构之间存在不一致(字符串不是 ObjectId!)。 elemMatch 成功返回我想要的!
-
@SteveHolgado 我担心如果字段是数组, find({employees: userId}) 将无法工作,但我已经尝试过了,并且也成功地工作了。谢谢你们!