2017-08-17 119 views
2

是嵌套数组第一个元素我有以下文件:查找符合条件

doc1: { 
    'array': [ 
    {'field': 'ABC', 'enabled': 'false'}, 
    {'field': 'BCD', 'enabled': 'true'}, 
    {'field': 'DEF', 'enabled': 'false'}, 
    {'field': 'XYZ', 'enabled': 'true'}, 
    ] 
} 


doc2: { 
    'array': [ 
    {'field': 'ABC', 'enabled': 'true'}, 
    {'field': 'BCD', 'enabled': 'true'}, 
    {'field': 'DEF', 'enabled': 'false'}, 
    {'field': 'XYZ', 'enabled': 'true'}, 
    ] 
} 

我对由特定领域的搜索。 我想获取启用此字段的所有文档,并且在此之前(在列表中)没有启用其他字段。

对于前:

搜索领域:BCD,启用:真正的 - 应该只返回第一个文件(因为第二个文档ABC中启用过)。

搜索XYZ,enabled:true - 根本不应该返回任何文档,因为在此列表的顶部还有其他字段已启用。

我试图做,但我不知道是否有可能在elemMatch匹配的元素顶部应用过滤器。

有什么建议吗?

回答

0

$where关键字允许为类似目的生成复杂的条件。

find($where: 'this.array.filter(function(e){return e.enabled=="true"})[0].field=="ABC"')

由于这种不使用任何索引,我会添加更多的条件,从优化中受益。

1

为什么不按enabled字段搜索,然后检查field是否合适?

db.collection("col").findOne({ 
    "array.enabled": true 
}, { 
    array: { 
     $elemMatch { 
      enabled: true 
     } 
    } 
}) 
.then(function(docs){ 
    docs.forEach(function(doc){ 
     if(doc.array[0].field == "ABC"){ 
      // Ok, we get it 
     } 
    }) 
}) 

第二参数find是投影,所以应用程序不会从文件下载完成阵列,但仅第一个匹配的它元件。

3

最可能搜索,除了正常的查询使用$where,仍然让事情在服务器上:

db.getCollection('collection').find({ 
    "array": { 
    "$elemMatch": { "field": "BCD", "enabled": "true" }, 
    }, 
    "$where": function() { 
    return this.array.map((e,i) => Object.assign(e,{ i })) 
     .filter(e => e.field === "BCD" && e.enabled === "true") 
     .map(e => e.i)[0] <= 
    this.array.map(e => e.enabled).indexOf("true") 
    } 
}) 

如果你有MongoDB的3.4与$indexOfArray$range支持,那么它可能看起来更长但它实际上最有效的与$redact

db.getCollection('collection').aggregate([ 
    { "$match": { 
    "array": { 
     "$elemMatch": { "field": "BCD", "enabled": "true" }, 
    } 
    }}, 
    { "$redact": { 
    "$cond": { 
     "if": { 
     "$lte": [ 
      { "$arrayElemAt": [ 
      { "$map": { 
       "input": { 
       "$filter": { 
        "input": { 
        "$map": { 
         "input": { 
         "$zip": { 
          "inputs": [ 
          "$array", 
          { "$range": [0, { "$size": "$array" }] } 
          ] 
         }  
         }, 
         "as": "a", 
         "in": { 
         "field": { "$arrayElemAt": [ "$$a.field", 0 ] }, 
         "enabled": { "$arrayElemAt": [ "$$a.enabled", 0 ] }, 
         "index": { "$arrayElemAt": [ "$$a", 1 ] }  
         } 
        } 
        }, 
        "as": "a", 
        "cond": { 
        "$and": [ 
         { "$eq": [ "$$a.field", "BCD" ] }, 
         { "$eq": [ "$$a.enabled", "true" ] } 
        ] 
        }  
       } 
       }, 
       "as": "a", 
       "in": "$$a.index" 
      }}, 
      0 
      ]}, 
      { "$indexOfArray": [ "$array.enabled", "true" ] } 
     ] 
     }, 
     "then": "$$KEEP", 
     "else": "$$PRUNE" 
    } 
    }} 
]) 

所以真的是强制执行,没有实际的查询操作,而这两种情况下保持“在服务器上”时,选择作为OPPO sed通过线路将数据发送到客户端,然后进行过滤。

因为如果你这样做,它首先会否定使用数据库的目的。所以你真的希望在服务器上发生这种情况。