[英]Mongodb check If field exists in an sub-document of an array
我正在嘗試檢查數組的子文檔中是否存在字段,如果存在,它將僅在回調中提供這些文檔。 但是每次我記錄回調文檔時,它都會給我數組中的所有值,而不是基於查詢的值。
我正在關注本教程,唯一的區別是我使用的是findOne function 而不是find function 但它仍然給了我所有的值。 我嘗試使用 find ,它做同樣的事情。
我也使用與上面鏈接中的示例相同的集合樣式。
例子 在上圖中,您可以在上圖中看到我有一個帶有uid字段和聯系人數組的文檔。 我要做的是首先 select 一個基於輸入uid的文檔。 然后在選擇該文檔后,我想顯示contacts.uid字段存在的contacts數組中的值。 因此,從上圖中,僅顯示的值是contacts[0]和contacts[3] ,因為contacts 1沒有 uid 字段。
Contact.contactModel.findOne({$and: [
{uid: self.uid},
{contacts: {
$elemMatch: {
uid: {
$exists: true,
$ne: undefined,
}
}
}}
]}
在您上面提到的教程中,他們將 2 個參數傳遞給該方法,一個用於過濾器,一個用於投影,但您只傳遞了一個,這就是區別。 您可以將查詢更改為:
Contact.contactModel.findOne(
{uid: self.uid},
{contacts: {
$elemMatch: {
uid: {
$exists: true,
$ne: undefined,
}
}
}}
)
agg 框架使過濾字段的存在變得有點棘手。 我相信 OP 想要一個字段存在於子文檔數組中的所有文檔,然后只返回那些存在該字段的子文檔。 以下應該可以解決問題:
var inputtedUID = "0"; // doesn't matter
db.foo.aggregate(
[
// This $match finds the docs with our input UID:
{$match: {"uid": inputtedUID }}
// ... and the $addFields/$filter will strip out those entries in contacts where contacts.uid does NOT exist. We wish we could use {cond: {$zz.name: {$exists:true} }} but
// we cannot use $exists here so we need the convoluted $ifNull treatment. Note we
// overwrite the original contacts with the filtered contacts:
,{$addFields: {contacts: {$filter: {
input: "$contacts",
as: "zz",
cond: {$ne: [ {$ifNull:["$$zz.uid",null]}, null]}
}}
}}
,{$limit:1} // just get 1 like findOne()
]);
show(c);
{
"_id" : 0,
"uid" : 0,
"contacts" : [
{
"uid" : "buzz",
"n" : 1
},
{
"uid" : "dave",
"n" : 2
}
]
}
您的問題來自對 MongoDB 中的數據建模的誤解,這對於來自其他 DBMS 的開發人員來說並不少見。 讓我通過數據建模如何與 RDBMS 與 MongoDB(以及許多其他 NoSQL 數據庫)一起工作的示例來說明這一點。
使用 RDBMS,您可以識別您的實體及其屬性。 接下來,您識別關系,規范化數據 model 並將您的數據撞到牆上,以獲得UPPER LEFT ABOVE AND BEYOND JOIN
™,這將回答用例 A 產生的問題。然后,您幾乎做同樣的事情對於用例 B。
使用 MongoDB,您可以顛倒過來。 查看您的用例,您將嘗試找出回答用例產生的問題所需的信息,然后 model 您的數據,以便以最有效的方式回答這些問題。
讓我們堅持您的聯系人數據庫示例。 這里需要做一些假設:
對於第一個假設,將聯系人嵌入到用戶文檔中是沒有問題的,因為存在文檔大小限制。 關於我們的第二個假設: uid
字段變得不是多余的,而只是無用的,因為已經有_id
字段唯一地標識了所討論的數據集。
讓我們看一些用例,這些用例是為了示例而簡化的,但它會給你圖片。
{
"_id": new ObjectId(),
"name": new String(),
"whatever": {}
}
{
"_id": new ObjectId(),
"contactOf": ObjectId(),
"name": new String(),
"phone": new String()
}
顯然, contactOf
指的是一個 ObjectId,它必須存在於 User 集合中。
給定一個用戶,我想找到一個聯系人。
如果我有用戶 object,我有它的_id
,單個聯系人的查詢變得像
db.contacts.findOne({"contactOf":self._id})
給定一個用戶,我想找到他的所有聯系人。
同樣容易:
db.contacts.find({"contactOf":self._id})
給定一個用戶,我想找到他的聯系人“John Doe”的詳細信息
db.contacts.find({"contactOf":self._id,"name":"John Doe"})
現在我們有了一種或另一種方式的聯系人,包括他/她/未決定/選擇不說_id
,我們可以輕松編輯/刪除它:
給定一個聯系人,我想對其進行編輯。
db.contacts.update({"_id":contact._id},{$set:{"name":"John F Doe"}})
我相信您現在已經了解如何從我們用戶的聯系人中刪除 John。
使用您的數據 model,您將需要為uid
字段添加額外的索引 - 正如我們發現的那樣,這沒有任何作用。 此外, _id
是默認索引的,所以我們很好地利用了這個索引。 但是,應該對contact
集合進行附加索引:
db.contact.ensureIndex({"contactOf":1,"name":1})
這里根本沒有完成。 造成這種情況的原因是多方面的,但最重要的是,雖然 John Doe 可能只有“Mallory H Ousefriend”的手機號碼,但他的妻子 Jane Doe 也可能擁有 email 地址“janes_naughty_boy@censored.com” -至少馬洛里肯定不想出現在約翰的聯系人列表中。 因此,即使我們有聯系人的身份,您也很可能不想反映這一點。
通過一些數據重構,我們將需要的附加索引數量減少到 1,使查詢更加簡單,並規避了 BSON 文檔大小限制。 至於性能,我想我們說的是至少一個數量級。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.