簡體   English   中英

匹配所有數組成員不包含值的文檔

[英]Match Documents where all array members do not contain a value

MongoDB選擇器變得非常復雜,特別是當您使用JOIN和其他花哨的關鍵字來自mySQL時。 我盡力使這個問題的標題盡可能清楚,但卻失敗了。

例如,讓MongoDB集合的文檔具有以下模式:

{
    _id : int
    products : [
        {
            qte : int
            status : string
        },            
        {
            qte : int
            status : string
        },
        {
            qte : int
            status : string
        },
        ...
    ]
}

我正在嘗試運行db.collection.find({ })查詢返回所有產品沒有字符串“已完成”作為狀態的文檔。 請注意, products數組的長度可變。

我們還可以說我們希望所有至少有一個產品的狀態都沒有“完成”的文檔。

如果我將它作為Javascript循環運行,我們會有以下內容:

// Will contain queried documents
var matches = new Array();

// The documents variable contains all documents of the collection
for (var i = 0, len = documents.length; i < len; i++) {
    var match = false;

    if (documents[i].products && documents[i].products.length !== 0) {
        for (var j = 0; j < documents[i].products; j++) {
            if (documents[i].products[j].status !== "finished") {
                match = true;
                break;
            }
        }
    } 

    if (match) {
        matches.push(documents[i]);
    }
}

// The previous snippet was coded directly in the Stack Overflow textarea; I might have done nasty typos.

matches數組將包含我正在尋找的文檔。 現在,我希望有一種類似於collection.find({"products.$.status" : {"$ne":"finished"}})但是當我這樣做時,MongoDB討厭我的臉。

此外,沒有任何產品的文檔需要被忽略,但我已經用$and子句想出了這個。 請注意,我需要退回整個文檔,而不僅僅是產品陣列。 如果文檔的產品未“完成”,則應存在整個文檔。 如果文檔的所有產品都設置為“已完成”,則根本不會返回該文檔。

MongoDB版本 :3.2.4

假設我們有一個包含三個文檔的集合。

這個匹配是因為其中一個狀態沒有“完成”。

{
    _id : 1,
    products : [
        {
            qte : 10,
            status : "finished"
        },
        {
            qte : 21,
            status : "ongoing"
        },
    ]
}

這不匹配,因為所有狀態都設置為“已完成”

{
    _id : 2,
    products : [
        {
            qte : 35,
            status : "finished"
        },
        {
            qte : 210,
            status : "finished"
        },
        {
            qte : 2,
            status : "finished"
        },
    ]
}

這也不匹配,因為沒有產品。 如果products字段未定義,它也不匹配。

{
    _id : 3,
    products : []
}

同樣,如果我們在本例中包含三個文檔的集合中運行查詢,則輸出將為:

[
    {
        _id : 1,
        products : [
            {
                qte : 10,
                status : "finished"
            },
            {
                qte : 21,
                status : "ongoing"
            },
        ]
    }
]

只返回第一個文檔,因為它至少有一個產品沒有“已完成”狀態,但最后兩個沒有進行切割,因為他們要么將所有產品的狀態設置為“已完成”,或者根本沒有任何產品。

嘗試以下查詢。 它正在獲取狀態不等於"finished"文檔

注意:此查詢僅適用於MongoDB 3.2+

db.collection.aggregate([
    {
      $project:{
        "projectid" : 1,
        "campname" : 1,
        "campstatus" : 1,
        "clientid" : 1,
        "paymentreq" : 1,
        products:{
          $filter:{
            input:"$products", 
            as: "product", 
            cond:{$ne: ["$$product.status", "finished"]}
           }
        }
      }
    },
    {
      $match:{"products":{$gt: [0, {$size:"products"}]}}
    }
])

你需要.aggregate()而不是.find() 這是確定所有元素是否實際上不包含所需內容的唯一方法:

// Sample data
db.products.insertMany([
  { "products": [
    { "qte": 1 },
    { "status": "finished" },
    { "status": "working" }
  ]},
  { "products": [
    { "qte": 2 },
    { "status": "working" },
    { "status": "other" }
  ]}
])

然后使用$redact進行聚合操作:

db.products.aggregate([
  { "$redact": {
    "$cond": {
      "if": {
        "$anyElementTrue": [
          { "$map": {
            "input": "$products",
            "as": "product",
            "in": { 
              "$eq": [ "$$product.status", "finshed" ]
            }
          }}
        ]
      },
      "then": "$$PRUNE",
      "else": "$$KEEP"
    }
  }}
])

或者你可以使用較差和較慢的堂兄與$where

db.products.find(function(){
  return !this.products.some(function(product){
    return product.status == "finished"
  })
})

兩者都只返回一個示例文檔:

{
        "_id" : ObjectId("56fb4791ae26432047413455"),
        "products" : [
                {
                        "qte" : 2
                },
                {
                        "status" : "working"
                },
                {
                        "status" : "other"
                }
        ]
}

因此帶有$map輸入的$anyElementTrue.some()基本上在這里做同樣的事情,並評估是否有任何匹配。 您使用“否定”斷言來“排除”實際找到匹配項的文檔。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM