MongoDB中如何在一定条件下从数组中获取特定对象

MongoDB中如何在一定条件下从数组中获取特定对象,mongodb,mongodb-query,aggregation-framework,Mongodb,Mongodb Query,Aggregation Framework,我的MongoDB中有以下数据结构: [ { "_id" : "**************", "primaryKey" : 1, "currentState" : [ { "value" : 5, "status" : "Y" }, { "value" : 5, "status" : "N" } ], "futureState" : { "value"

我的MongoDB中有以下数据结构:

[
 {
  "_id" : "**************",
  "primaryKey" : 1,
  "currentState" : [ 
    {
        "value" : 5,
        "status"  : "Y"
    },
    {
        "value" : 5,
        "status"  : "N"
    }
  ],
  "futureState" : {
        "value" : 5,
        "status"  : "F"
    }
 },
 {
  "_id" : "**************",
  "primaryKey" : 2,
  "currentState" : [ 
    {
        "value" : 5,
        "status"  : "N"
    }
  ],
  "futureState" : {}
 }
]
我只想获取状态Y为currentState字段的对象,并在另一个文档中获取相应的futureState字段

预期产出:


我不知道如何在MongoDB中获取这些数据,请帮助我。谢谢

您可以通过两种方式完成:

聚集 JS
您可以使用以下查询来执行此操作:

db.collection.aggregate([
    /** First match is optional for small dataset but highly preferred to filter required docs from huge dataset */
    { $match: { 'currentState.status': 'Y' } },
    /** Retain only objects in currentState which has status == 'Y' & add a fake empty object to array  */
    { $addFields: { 'currentState': { $concatArrays: [{ $filter: { input: '$currentState', cond: { $eq: ['$$this.status', 'Y'] } } }, [{}]] } } },
    /** unwind currentState field across all docs */
    { $unwind: '$currentState' },
    /** if currentState is an object for a doc then keep that field & remove futureState else vice-versa  */
    {
        $addFields: {
            futureState: { $cond: [{ $ne: ['$currentState', {}] }, '$$REMOVE', '$futureState'] },
            currentState: { $cond: [{ $ne: ['$currentState', {}] }, '$currentState', '$$REMOVE'] }
        }
    }
])
测试:

db.collection.aggregate([
  {
    $project: {
      doc1: {
        $filter: {
          input: {
            $map: {
              input: {
                $objectToArray: "$$ROOT"
              },
              as: "root",
              in: {
                k: "$$root.k",
                v: {
                  $cond: [
                    {
                      $eq: [
                        "$$root.k",
                        "currentState"
                      ]
                    },
                    {
                      $ifNull: [
                        {
                          $arrayElemAt: [
                            {
                              $filter: {
                                input: "$$root.v",
                                cond: {
                                  $eq: [
                                    "$$this.status",
                                    "Y"
                                  ]
                                }
                              }
                            },
                            0
                          ]
                        },
                        {}
                      ]
                    },
                    "$$root.v"
                  ]
                }
              }
            }
          },
          cond: {
            $ne: [
              "$$this.k",
              "futureState"
            ]
          }
        }
      },
      doc2: {
        $filter: {
          input: {
            $objectToArray: "$$ROOT"
          },
          cond: {
            $ne: [
              "$$this.k",
              "currentState"
            ]
          }
        }
      }
    }
  },
  {
    $project: {
      tmp: [
        {
          $arrayToObject: "$doc1"
        },
        {
          $arrayToObject: "$doc2"
        }
      ]
    }
  },
  {
    $unwind: "$tmp"
  },
  {
    $replaceWith: "$tmp"
  }
])
db.collection.find({}).forEach(function(doc){

    var aux          = Object.assign({}, doc);
    delete aux.currentState;

    doc.currentState = doc.currentState.filter(x => x.status == "Y");
    doc.currentState = doc.currentState.length > 0 ? doc.currentState[0] : {};
    delete doc.futureState;

    print(doc);
    print(aux);
})
db.collection.aggregate([
    /** First match is optional for small dataset but highly preferred to filter required docs from huge dataset */
    { $match: { 'currentState.status': 'Y' } },
    /** Retain only objects in currentState which has status == 'Y' & add a fake empty object to array  */
    { $addFields: { 'currentState': { $concatArrays: [{ $filter: { input: '$currentState', cond: { $eq: ['$$this.status', 'Y'] } } }, [{}]] } } },
    /** unwind currentState field across all docs */
    { $unwind: '$currentState' },
    /** if currentState is an object for a doc then keep that field & remove futureState else vice-versa  */
    {
        $addFields: {
            futureState: { $cond: [{ $ne: ['$currentState', {}] }, '$$REMOVE', '$futureState'] },
            currentState: { $cond: [{ $ne: ['$currentState', {}] }, '$currentState', '$$REMOVE'] }
        }
    }
])