我正在尝试检查数组的子文档中是否存在某个字段,如果存在,它将仅在回调中提供这些文档。但是每次我记录回调文档时,它都会给我数组中的所有值,而不是基于查询的值。
I am following this tutorial 唯一的区别是我使用 findOne 函数而不是 find 函数,但它仍然返回所有值。我尝试使用 find ,它做了同样的事情。
我还使用与上面链接中的示例相同的集合样式。
示例 在上图中,您可以在上图中看到我有一个带有 uid 字段和 contacts 数组的文档。我想做的是首先根据输入的uid选择一个文档。然后,选择该文档后,我想显示 contacts 数组中存在 contacts.uid 字段的值。因此,从上图中,仅显示的值是 contacts[0] 和 contacts[3],因为 contacts 1 没有 uid 字段。
Contact.contactModel.findOne({$and: [
{uid: self.uid},
{contacts: {
$elemMatch: {
uid: {
$exists: true,
$ne: undefined,
}
}
}}
]}
最佳答案
您的问题源于对 MongoDB 中数据建模的误解,这对于来自其他 DBMS 的开发人员来说并不罕见。让我通过数据建模如何使用 RDBMS 与 MongoDB(以及许多其他 NoSQL 数据库)的示例来说明这一点。
使用 RDBMS,您可以识别实体及其属性。接下来,您确定关系,规范化数据模型,然后将您的数据撞到墙上,以获得 UPPER LEFT ABOVE AND BEYOND JOIN
™,这将回答用例 A 中出现的问题。然后,对于用例 B,您几乎执行相同的操作。
使用 MongoDB,您将把这一切颠倒过来。查看您的用例,您将尝试找出回答用例中出现的问题所需的信息,然后对数据进行建模,以便以最有效的方式回答这些问题。
让我们继续使用您的联系人数据库示例。这里需要做一些假设:
- 每个用户可以拥有任意数量的联系人。
- 每个联系人和每个用户都需要通过名称以外的其他内容进行唯一标识,因为名称可能会发生变化等。
- 冗余并不是坏事。
根据第一个假设,将联系人嵌入到用户文档中是毫无疑问的,因为存在文档大小限制。关于我们的第二个假设:uid
字段变得不是多余的,而是毫无用处,因为已经有 _id
字段唯一标识数据集问题。
用例
让我们看一些用例,这些用例为了示例而进行了简化,但它会给您提供图片。
- 给定一个用户,我想找到一个联系人。
- 给定一个用户,我想找到他的所有联系人。
- 给定一个用户,我想查找他的联系人“John Doe”的详细信息
- 给定一个联系人,我想对其进行编辑。
- 给定一个联系人,我想将其删除。
数据模型
用户
{
"_id": new ObjectId(),
"name": new String(),
"whatever": {}
}
联系方式
{
"_id": new ObjectId(),
"contactOf": ObjectId(),
"name": new String(),
"phone": new String()
}
显然,contactOf
引用了一个必须存在于 User 集合中的 ObjectId。
实现
Given a user, I want to find a single contact.
如果我有用户对象,我就有它的_id
,并且查询单个联系人变得如此简单
db.contacts.findOne({"contactOf":self._id})
Given a user, I want to find all of his contacts.
同样简单:
db.contacts.find({"contactOf":self._id})
Given a user, I want to find the details of his contact "John Doe"
db.contacts.find({"contactOf":self._id,"name":"John Doe"})
现在我们已经有了这样或那样的联系人,包括他/她/未定/选择不说_id
,我们可以轻松地编辑/删除它:
Given a contact, I want to edit it.
db.contacts.update({"_id":contact._id},{$set:{"name":"John F Doe"}})
我相信现在您已经了解如何从我们用户的联系人中删除 John。
注释
指数
对于您的数据模型,您需要为 uid
字段添加额外的索引 - 正如我们发现的那样,这没有任何意义。此外,_id
默认是有索引的,所以我们充分利用这个索引。但是,应该在 contact
集合上建立一个额外的索引:
db.contact.ensureIndex({"contactOf":1,"name":1})
标准化
这里根本没有完成。造成这种情况的原因是多方面的,但最重要的是,虽然 John Doe 可能只有“Mallory H Ousefriend”的手机号码,但他的妻子 Jane Doe 可能也有电子邮件地址“janes_naughty_boy@censored.com” - 该地址位于至少马洛里肯定不想出现在约翰的联系人列表中。因此,即使我们有联系人的身份,您也很可能不想反射(reflect)这一点。
结论
通过一些数据重构,我们将所需的附加索引数量减少到 1,使查询变得更加简单,并规避了 BSON 文档大小限制。至于性能,我想我们正在谈论至少一个数量级。
关于javascript - Mongodb 检查数组的子文档中是否存在字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58249498/