【问题标题】:Mongoose, find by element in arrayMongoose,按数组中的元素查找
【发布时间】:2020-07-08 17:10:09
【问题描述】:

我正在尝试使用 Mongoose 和 Node.js 在数组字段中查找具有特定值的所有文档。我可以在 MongoDB 中毫无困难地做到这一点,但我在 Mongoose 中遇到了困难。我使用Find document with array that contains a specific value 作为我如何做到这一点的指南,但我没有得到我期望的结果。 我的模型:

const mongoose = require("mongoose");

const Schema = mongoose.Schema;
const ApptSchema = new Schema({
  store: { type: String, required: true },
  dotw: { type: String, required: true },
  month: { type: Number, required: true },
  day: { type: Number, required: true },
  hr: { type: Number, required: true },
  min: { type: Number, required: true },
  customers: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }],
  full: { type: Boolean, required: true, default: false }
});

const Appt = mongoose.model("Appt", ApptSchema);

module.exports = Appt;

我想查找所有包含特定客户 ID 的文档。在 MongoDB shell 中,我会这样做:

db.appts.find({customers: "5e7e3bc4ac4f196474d8bf69"})

这按预期工作,为我提供了所有文档(在本例中为一个文档),其中此 id 在 customers 数组中。

{ "_id" : ObjectId("5e7e719c806ef76b35b4fd69"), "customers" : [ "5e7e3bc4ac4f196474d8bf69" ], "full" : false, "store" : "Nashville", "dotw" : "Friday", "month" : 4, "day" : 15, "hr" : 13, "min" : 0 }

在猫鼬中,这是我正在尝试的:

Appt.find({ customers: "5e7e3bc4ac4f196474d8bf69" }, (err, docs) => {
    if (err) {
      console.log(err);
    } else {
      console.log(docs);
    }
  });

这会打印一个空数组,即使在 customers 数组中明确有一个文档,该 id 也是如此。 这似乎应该可行,但我显然错过了一些难题。非常感谢任何对我做错了什么的见解。

编辑:如果有人想/愿意进行更深入的研究,到目前为止可以找到该应用程序的 GitHub 存储库here。有问题的查询位于第 111 行的 routes/routes.js 中(截至撰写本文时)。

另一个编辑:这似乎与相关字段的架构类型有关。我消除了customers 字段中条目的ref 属性,以防万一这会导致问题,但我的查询仍然返回一个空数组。下一个测试是在我的模型中添加一个新字段myStrings: [String]。然后,我在我的一个 Appt 文档 "working" 的数组中添加了一个字符串,并查询了 Appt.find({myStrings: "working"}),这最终返回了我更新的 Appt 文档。这告诉我使用mongoose.Schema.Types.ObjectId 有一些奇怪的地方,但我不知道如何解决它。

最终编辑:经过多次磨难,这个问题解决了。问题如下... 为了测试,我使用 MongoDB shell 将项目添加到我的数据库中,它不像 Mongoose 那样强制执行数据类型。我没有意识到我只是将用户 ID 作为字符串添加到 customers 数组中。当 Mongoose 去寻找 ObjectIds 时,它当然没有找到,并返回一个空数组。使用db.appts.updateOne({<whatever information>},{$push:{customers: new ObjectId(<id string>)}}) 将客户添加到customers 数组中,Mongoose 能够返回我正在寻找的信息。

【问题讨论】:

  • 查询正确 (mongoplayground.net/p/Q9firU4-_0l),请确保您从 Mongoshell 和 mongoose 查询相同的数据库/集合。
  • 感谢您的建议。这绝对是同一个数据库/集合。如果我查询 Appt.find({ _id: "5e7e719c806ef76b35b4fd69" }),我会返回与 MongoDB shell 查询 db.appts.find({_id: ObjectId("5e7e719c806ef76b35b4fd69")}) 相同的文档,其中包含我在 customers 数组中寻找的用户。
  • 这个答案给你三个解决这个问题的方法:stackoverflow.com/questions/63368225/…
  • This answer 给你三个解决这个问题的办法。

标签: arrays node.js mongodb mongoose


【解决方案1】:

我想说你的问题是你在过滤器中使用了一个字符串,其中的字段是ObjectId 类型。因此,需要先将字符串转换为ObjectId,mongoose才能正确查询。

Appt.find({ customers: mongoose.Types.ObjectId("5e7e3bc4ac4f196474d8bf69") }, (err, docs) => {});

【讨论】:

  • 我相信字符串会自动转换为 ObjectId。如果我用一个不同的字符串代替一个有效的 id,它会抛出一个强制转换错误。例如,Appt.find({customers: "fish"}),将抛出错误,MongooseError [CastError]: Cast to ObjectId failed for value "fish" at path "customers" for model "Appt"。以防万一,我确实尝试按照您的建议将字符串显式转换为 ObjectId,但我仍然得到一个空数组作为回报。不过还是谢谢你的建议!
  • @LuosRestil CastError 通常被触发,因为您传入的字符串长度不正确:Error: Argument passed in must be a single String of 12 bytes or a string of 24 hex characters 我的代码中的以下工作:javascript const experiments = await Experiment.find({ participants: mongoose.Types.ObjectId(participantId) }); res.json({experiments}); };
  • 奇怪!如果我这样做Appt.find({customers: mongoose.Types.ObjectId("5e7e3bc4ac4f196474d8bf69")}, (err, docs) => console.log(docs)),我仍然会得到一个空数组。我想知道我在做什么不同?
  • 确实很奇怪!因为我正在做一些测试,它实际上对我有用,而无需将其转换为 ObjectId ......所以你的原始代码对我来说实际上看起来不错。如果您将其构建为 API,请确保您从路由器正确获取 id。
  • 不用担心尝试从路由器获取 id,我已经继续硬编码一个已知的工作用户 id 以进行调试。
【解决方案2】:

添加 _id 字段:

Appt.find({ customers._id: "5e7e3bc4ac4f196474d8bf69" }, (err, docs) => {
if (err) {
  console.log(err);
} else {
  console.log(docs);
}});

【讨论】:

  • 恐怕这也会返回一个空数组。谢谢你的建议,但没有运气。
  • 我没有注意到您正在使用 ref:user。您可能想要使用 POPULATE。如果你能告诉我你到底想做什么并搜索。那会很好
  • 我认为我不需要为此任务使用填充,因为我不需要收集有关其 id 存储在 customers 数组中的用户的任何信息。我只是想通过用户 ID 查找约会(Appt),在他们的customers 列表中获取所有具有该 ID 的约会的列表。
  • 当您在客户中使用 REF 时:[{ type: mongoose.Schema.Types.ObjectId, ref: "User" }]。除了使用填充之外,没有其他方法可以通过 appt 集合查询用户 ID。除非 CUSTOMERS 字段只是一个未引用到另一个集合的子文档的简单数组。如果您尝试通过用户 ID 查找 appts,您可能希望更改您的用户架构并在那里添加 appt 引用。所以反过来。
  • 这对我来说很有意义,所以我继续删除了ref,并把它变成了一个正常的字段。不幸的是,这个查询仍然返回一个空数组。
猜你喜欢
  • 2014-05-21
  • 2017-12-05
  • 2019-08-09
  • 1970-01-01
  • 2021-05-27
  • 1970-01-01
  • 1970-01-01
  • 2012-09-26
  • 2014-05-19
相关资源
最近更新 更多