2013-10-08 93 views
1

是否有一種方法可以使用db.collection.find()來查詢子文檔中的特定值並查找匹配的文檔。例如:在子文檔中使用db.collection.find查詢

{{ '喬':{眼睛顏色: '棕'},{ '瑪麗':{眼睛顏色: '藍'}, .... }

我想返回眼睛顏色爲藍色的所有人的姓名。

+0

因此這是一個非常糟糕的設計 –

回答

3

你需要指定的值的完整路徑,搜索工作:

db.people.find({ "Joe.eyecolor" : "brown" }) 

您不能切換到人數組,而不是你現在正在使用的關聯數組的風格,有沒有辦法只返回符合條件的數組元素。您可以使用$elemMatch返回第一個匹配項,但這不可能是您想要的。或者,您仍然可以使用數組,但是您需要在客戶端代碼(而不是數據庫)中進一步過濾數組。

您可能可以使用Aggregation框架,但它不會有效地使用索引,因爲您需要對整個數組使用$unwind,然後執行過濾,強力操作。如果包含的數據更加複雜,那麼使用AF時的投影要求您手動指定所有字段,這會變得有點麻煩。

爲了最有效地做你的顯示查詢,你需要不使用子文檔,而是把人作爲單獨的文件:

{ 
    name: "Joe", 
    eyecolor: "brown" 
} 

然後,你可以只是做一個簡單的搜索像:

db.people.find({eyecolor: "brown"}) 
0

是和否。您可以查詢具有匹配人員的所有文檔,但無法直接查詢所有人員。換句話說,子文檔不是虛擬集合,您將始終返回「父」文檔。

您發佈的示例帶有額外的複雜性,您將該名稱用作字段鍵,這會阻止您使用點符號。

一般來說,如果您有許多類似的事情,最好將它們放在一個列表中,例如,

{ 
    "_id" : 132, 
    "ppl" : [ { "Name" : "John", "eyecolor" : "blue" }, 
      { "Name" : "Mary", "eyecolor" : "brown" }, 
      ... 
      ] 
} 

然後,您可以查詢使用聚合框架:

db.collection.aggregate([ 
// only match documents that have a person w/ blue eyes (can use indexing) 
{$match : { "ppl.eyecolor" : "blue" } }, 
// unwind the array of people 
{$unwind : "$ppl" }, 
// match only those with blue eyes 
{$match : { "ppl.eyecolor" : "blue" }}, 
// optional projection to make the result a list of people 
{$project : { Name : "$ppl.Name", EyeColor: "$ppl.eyecolor" }} ]); 

其中給出像

"result" : [ 
    { 
      "_id" : 132, 
      "Name" : "John", 
      "EyeColor" : "blue" 
    }, 
    { 
      "_id" : 12, 
      "Name" : "Jimmy", 
      "EyeColor" : "blue" 
    }, 
    { 
      "_id" : 4312, 
      "Name" : "Jimmy", 
      "EyeColor" : "blue" 
    }, 
    { 
      "_id" : 4312, 
      "Name" : "Marc", 
      "EyeColor" : "blue" 
    } 
], 
"ok" : 1