PHP mongo - 对特定数组值的投影

时间:2015-04-17 15:36:16

标签: mongodb aggregation-framework

我有以下查询:

$aggregate = [
        ['$unwind' => '$positions'],
        ['$match' => ['positions.banner_params.project_location_id' => (int)$projectId]],
        [
            '$project' => [
                'page_id' => '$_id',
                'position_id' => '$positions.id',
                'page' => [
                    'website_id' => '$website_id',
                    'rate_tic' => '$rate_tic',
                ],
                'banner_params' => [
                    'title' =>  '$positions.banner_params.title',
                    'tmpl_id' =>  '$positions.banner_params.tmpl_id'
                ],
                'tmpl' => '$positions.tmpls',
                '_id' => 0
            ]
        ],
    ];
    $rows = $collection->aggregate($aggregate);

它会返回这样的结果:

[0] => Array
    (
        [page_id] => MongoId Object
            (
                [$id] => 5527a3a276098d86ae9aa3aa
            )

        [position_id] => 1
        [page] => Array
            (
                [website_id] => 41
                [rate_tic] => 10
            )

        [banner_params] => Array
            (
                [title] => My Title
                [tmpl_id] => 2
            )

        [tmpl] => Array
            (
                [0] => Array
                    (
                        [id] => 1
                        [width] => 500
                        [height] => 100
                    )

                [1] => Array
                    (
                        [id] => 2
                        [width] => 160
                        [height] => 400
                    )

                [2] => Array
                    (
                        [id] => 7
                        [width] => 384
                        [height] => 115
                    )

            )

    )

如何进入tmpl只有与banner_params.tmpl_id匹配的模板?

2 个答案:

答案 0 :(得分:0)

首先让我确定我是否理解正确。您希望按[tmpl] => Array过滤[id]中的项目。

你不能直接这样做,因为[tmpl]是一个嵌入式对象,但是由于聚合是一个管道函数,你可以按照你可以过滤的方式转换当前输出,然后用$unwind再次用{$match过滤它。 1}}并最终使用$group获取所需的文档。像下面的代码应该达到你想要的;

    $aggregate = [
        ['$unwind' => '$positions'],
        ['$match' => ['positions.banner_params.project_location_id' => (int)$projectId]],
        [
            '$project' => [
                'page_id' => '$_id',
                'position_id' => '$positions.id',
                'page' => [
                    'website_id' => '$website_id',
                    'rate_tic' => '$rate_tic',
                ],
                'banner_params' => [
                    'title' =>  '$positions.banner_params.title',
                    'tmpl_id' =>  '$positions.banner_params.tmpl_id'
                ],
                'tmpl' => '$positions.tmpls',
                '_id' => 0
            ]
        ],
        ['$unwind' => '$tmpl'], // makes every item as a colection
        ['$match' => ['tmpl.id' => (int)$your id]], //filter the records
        ['$group' => ['_id' => '$page_id', tmpl:{$push:"$tmpl"} ]] // rebuild collection as you wanted you can use a compound _id if this is not enough
        //if you don t want to see _id apply another projections to change it.
    ];
    $rows = $collection->aggregate($aggregate);

可能有一些错误,但这是你应该实现的逻辑。

编辑:

还有$redact DOC删除子文档中的项目,请参阅示例。

  

根据存储的信息限制文档的内容   文件本身。

答案 1 :(得分:0)

好的,感谢Onur TOPAL's建议我找到了解决方案。还有一个$ unvind后跟$ redact完成了这项工作。

$aggregate = [
    ['$unwind' => '$positions'],
    ['$match' => ['positions.banner_params.project_location_id' => (int)$projectId]],
    [
        '$project' => [
            'page_id' => '$_id',
            'position_id' => '$positions.id',
            'page' => [
                'website_id' => '$website_id',
                'rate_tic' => '$rate_tic',
            ],
            'banner_params' => [
                'title' =>  '$positions.banner_params.title',
                'tmpl_id' =>  '$positions.banner_params.tmpl_id'
            ],
            'tmpl' => '$positions.tmpls',
            '_id' => 0
        ]
    ],
    ['$unwind' => '$tmpl'],
    [
        '$redact' => [
            '$cond' => [
                'if' => ['$eq' => ['$tmpl.id', '$banner_params.tmpl_id']],
                'then' => '$$KEEP',
                'else' => '$$PRUNE'
            ]
        ]
    ]
];