在嵌套数组中搜索对象:如何仅返回找到的对象和父元素?

问题描述 投票:0回答:1

以下是

pictures
MongoDB 集合的摘录:

[
  {
    "_id": "57582b6b",
    "source": "integration",
    "url": "https://example.com/images/51/landscapes-polar.xml",
    "pictures": [
      {
        "name": "pines",
        "version": "2"
      },
      {
        "name": "penguins",
        "version": "1"
      },
      {
        "name": "pineapple",
        "version": "7"
      }
    ]
  },
  {
    "_id": "57582b6d",
    "source": "customer",
    "url": "https://example.com/images/15/nature.xml",
    "pictures": [
      {
        "name": "mountains",
        "version": "2"
      },
      {
        "name": "pines",
        "version": "1"
      }
    ]
  },
  {
    "_id": "57582b6c",
    "source": "qa",
    "url": "https://example.com/image/32/landscapes.xml",
    "pictures": [
      {
        "name": "alps",
        "version": "1"
      },
      {
        "name": "pineapple",
        "version": "7"
      },
      {
        "name": "pines",
        "version": "3"
      }
    ]
  }
]

我主要关心的是从嵌套的

names
数组内部找到特定的
pictures
。当找到与部分查询字符串匹配的名称时,它们应保留在
pictures
数组中,并与
pictures
的父数组一起显示。使用 PyMongo 库,我能够使用此函数检索查询的数据:

import re
from flask import Flask, jsonify

from controller.database import client, database_name, temp_collection


app = Flask(__name__)
db = client[database_name]
collection = db[temp_collection]


@app.route('/component/find/<picture_name>', methods=['GET'])
def get_component(picture_name):
    pattern = re.compile(picture_name, re.IGNORECASE)

    pipeline = [
        {"$unwind": "$pictures"},
        {"$match": {"pictures.name": {"$regex": pattern}}},
        {"$group": {
            "_id": "$_id",
            "url": {"$first": "$url"},
            "source": {"$first": "$source"},
            "pictures": {"$addToSet": "$pictures"},
            "root": {"$first": "$$ROOT"}
        }},
        {"$replaceRoot": {
            "newRoot": {
                "$mergeObjects": ["$root", {"pictures": "$pictures"}]
            }
        }},
        {"$project": {
            "_id": {"$toString": "$_id"},
            "url": 1,
            "source": 1,
            "pictures": 1
        }}
    ]

    result = list(collection.aggregate(pipeline))

    if result:
        return jsonify(result)
    else:
        return jsonify({"message": "Component with picture '{}' not found.".format(picture_name)}), 404


if __name__ == "__main__":
    app.run(debug=True)

但是,检索到的数据仅包含单元素

pictures
数组,而不是放入所有匹配的对象。

换句话说,这就是我想要得到的:

[
  {
    "_id": "57582b6b",
    "source": "integration",
    "url": "https://example.com/51/landscapes-polar.xml",
    "pictures": [
      {
        "name": "pines",
        "version": "2"
      },
      {
        "name": "pineapple",
        "version": "7"
      }
    ]
  },
  {
    "_id": "57582b6d",
    "source": "customer",
    "url": "https://example.com/15/nature.xml",
    "pictures": [
      {
        "name": "pines",
        "version": "1"
      }
    ]
  },
  {
    "_id": "57582b6c",
    "source": "qa",
    "url": "https://example.com/image/32/landscapes.xml",
    "pictures": [
      {
        "name": "pineapple",
        "version": "7"
      },
      {
        "name": "pines",
        "version": "3"
      }
    ]
  }
]

这就是我现在得到的:

[
  {
    "_id": "57582b6b",
    "source": "integration",
    "url": "https://example.com/51/landscapes-polar.xml",
    "pictures": [
      {
        "name": "pines",
        "version": "2"
      }
    ]
  },
  {
    "_id": "57582b6d",
    "source": "customer",
    "url": "https://example.com/15/nature.xml",
    "pictures": [
      {
        "name": "pines",
        "version": "1"
      }
    ]
  },
  {
    "_id": "57582b6c",
    "source": "qa",
    "url": "https://example.com/image/32/landscapes.xml",
    "pictures": [
      {
        "name": "pineapple",
        "version": "7"
      }
    ]
  }
]

如何确保所有匹配的

pictures
对象都被推送到正确的数组? (使用
$push
代替
$addToSet
会返回相同的结果。)

python json flask pymongo
1个回答
0
投票

使用 Mongo Playground,我能够逐步构建查询,并发现删除一些标记会得到我想要的内容。 Flask 应用程序应该这样设置:

import re
from flask import Flask, jsonify

from controller.database import client, database_name, temp_collection


app = Flask(__name__)
db = client[database_name]
collection = db[temp_collection]


@app.route('/component/find/<picture_name>', methods=['GET'])
def get_component(picture_name):
    pattern = re.compile(picture_name, re.IGNORECASE)

    pipeline = [
        {"$unwind": "$pictures"},
        {"$match": {"pictures.name": {"$regex": pattern}}},
        {"$group": {
            "_id": {"$toString": "$_id"}, # convert _id to str
            "url": {"$first": "$url"},
            "source": {"$first": "$source"},
            "pictures": {"$addToSet": "$pictures"}
        }}
    ]

    result = list(collection.aggregate(pipeline))

    if result:
        return jsonify(result)
    else:
        return jsonify({"message": "Component with picture '{}' not found.".format(picture_name)}), 404


if __name__ == "__main__":
    app.run(debug=True)
© www.soinside.com 2019 - 2024. All rights reserved.