如何在mongodb中从数组中排除特定对象?

时间:2017-10-29 15:03:12

标签: mongodb projection

我有一个具有以下结构的集合:

{
        "_id" : ObjectId("59ef54445134d7d70e1cf531"),
        "CustomerId" : "Gym_2",
        "History" : [
                {
                        "Created_At" : ISODate("2017-10-24T14:54:59Z"),
                        "Unit" : 600,
                        "ReferenceCode" : "1cd15b4d-bc42-4a51-a8b3-307db6dc3dee",

                },
                {
                        "Created_At" : ISODate("2017-10-28T00:22:19Z"),
                        "Sent" : true
                },
                {
                        "Created_At" : ISODate("2017-10-29T10:22:23Z"),
                        "Unit" : 600,
                        "ReferenceCode" : "998e7fce-8a1c-4f7c-b48c-c02cb5c5ad5c",
                }
        ]
}
{
        "_id" : ObjectId("59ef54465134d7d70e1cf534"),
        "CustomerId" : "Gym_1",
        "History" : [
                {
                        "Created_At" : ISODate("2017-10-24T14:55:02Z"),
                        "Unit" : 600,
                        "ReferenceCode" : "d19ebeec-bd81-4a0a-aed5-006f746b50ff",
                },
                {
                        "Unit" : 600,
                        "ReferenceCode" : "a991504f-be1f-4e77-b59f-fba73c59e6f1",
                        "Created_At" : ISODate("2017-10-26T13:51:14Z")
                }
        ]
}

我尝试构建一个只返回CustomerId的查询以及没有设置"Sent"字段的历史对象。 结果应如下所示:

       {
                "_id" : ObjectId("59ef54445134d7d70e1cf531"),
                "CustomerId" : "Gym_2",
                "History" : [
                        {
                                "Created_At" : ISODate("2017-10-24T14:54:59Z"),
                                "Unit" : 600,
                                "ReferenceCode" : "1cd15b4d-bc42-4a51-a8b3-307db6dc3dee",

                        },

    {
                            "Created_At" : ISODate("2017-10-29T10:22:23Z"),
                            "Unit" : 600,
                            "ReferenceCode" : "998e7fce-8a1c-4f7c-b48c-c02cb5c5ad5c",
                    }
            ]
    }
    {
            "_id" : ObjectId("59ef54465134d7d70e1cf534"),
            "CustomerId" : "Gym_1",
            "History" : [
                    {
                            "Created_At" : ISODate("2017-10-24T14:55:02Z"),
                            "Unit" : 600,
                            "ReferenceCode" : "d19ebeec-bd81-4a0a-aed5-006f746b50ff",
                    },
                    {
                            "Unit" : 600,
                            "ReferenceCode" : "a991504f-be1f-4e77-b59f-fba73c59e6f1",
                            "Created_At" : ISODate("2017-10-26T13:51:14Z")
                    }
            ]
    }

我能够达到的最接近的是以下查询:

db.Customers.aggregate([ 
  {$project:{"Sent":{$exists:false},count:{$size:"$History" }}}
  ]);  

但我得"errmsg" : "Unrecognized expression '$exists'"。 我怎样才能达到这个结果?

1 个答案:

答案 0 :(得分:1)

您的问题有一个解决方案,聚合框架绝对是实现您想要的正确方法。要修改嵌套集合,您必须:

  1. 展开此系列($ unwind)
  2. 过滤掉已存在的文档
  3. 按共同属性分组
  4. 投放您的数据以接收原始表格

    import java.io.FileWriter
    class Main{
    
        static void main(String[] args)
        {
    
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in))
            println "Enter the number of items:"
            int n = Integer.parseInt(br.readLine())
            String[] item =new String[n]
            Double[] price =new Double[n]
            int[] quantity = new int[n]
    
            for(int i=0; i<n;i++)
            {
                int it = i+1
                println "Enter item $it details: "
                item[i] = br.readLine()
                price[i] = Double.parseDouble(br.readLine()).round(2)
                quantity[i] = Integer.parseInt(br.readLine())
            }
    
            String COMMA_DELIMITER = ","
            String NEW_LINE_SEPARATOR = "\n"
    
            try
            {
                FileWriter fileWriter = new FileWriter("invoicedetails.csv")
    
                for(int j=0; j<n;j++)
                {
                    fileWriter.append(item[j])
                    fileWriter.append(COMMA_DELIMITER)
                    fileWriter.append(price[j])
                    fileWriter.append(COMMA_DELIMITER)
                    fileWriter.append(quantity[j])
                    fileWriter.append(NEW_LINE_SEPARATOR)   
                }
            }
            catch(Exception e)
            {
                println e
            } 
        }
    }
    
  5. 正如您所看到的,此查询相当复杂,对于较大的集合,您可能会遇到性能问题,因为我们做的不仅仅是简单的集合过滤。因此,虽然它有效但我建议您应该考虑更改数据模型,例如将每个历史项目作为单独的文档,如下所示:

    db.customers.aggregate([
       {$unwind: "$History"},
       {$match: {"History.Sent": {$exists: false}}},
       {$group: {"_id": { "_id": "$_id", "CustomerId": "$CustomerId" }, History: { $push: "$History"} }},
       {$project: { "_id": "$_id._id", "CustomerId": "$_id.CustomerId", History: 1}}
    ]);
    

    然后您的查询将只是简单查找$ exists。