使用PHP驱动程序深入查询MongoDB子集两个级别

时间:2012-04-05 15:24:47

标签: php json facebook-graph-api mongodb mongodb-php

我访问了Facebook Graph API,以获取一个JSON对象,代表我的Feed(我的Facebook墙上)的最新帖子。然后我使用PHP Mongo驱动程序将其保存到名为feeds的MongoDB集合中。

//$post['feed']['data'] contains the Facebook JSON object of wall posts
//create a mongo instance
$mongo = new Mongo();
//access the feeds collection
$feeds = $mongo->changeup->feeds;
//dump the feed right into mongo
$feeds->insert($post['feed']['data']);

这是在读回放入mongo的整个对象后,其中一个数组的样子。

我只给你一个,但它给了我几个,每个索引,下一个是[1] => Array()等......有些结构不同,有些包含[story]字段,有些包含[message]字段,有些包含两者。

Query:
$cursor = $feeds->find();

foreach ( $cursor as $feed ) { 
print_r($feed);
}

Result:
[0] => Array
        (
            [id] => 505212695_10150696450097696
            [from] => Array
                (
                    [name] => John Doe
                    [id] => 505212695
                )

            [story] => "Text of a story I posted on my wall..."
            [story_tags] => Array
                (
                    [38] => Array
                        (
                            [0] => Array
                                (
                                    [id] => 15212444
                                    [name] => John Doe
                                    [offset] => 38
                                    [length] => 10
                                    [type] => user
                                )

                        )

                )

            [type] => status
            [application] => Array
                (
                    [name] => Share_bookmarklet
                    [id] => 5085647995
                )

            [created_time] => 2012-04-04T05:51:21+0000
            [updated_time] => 2012-04-04T05:51:21+0000
            [comments] => Array
                (
                    [count] => 0
                )

)

问题是我不想只找到整个集合,我只想找到那些说[message]和[story]字段的数组,然后只找到它们的内容而不是别的。

我正在尝试接收两个级别的子集:

//this works, however, I'm only able to get the 0 array 
$cursor = $feeds->find( array(), array('0.story' => true) );

如何按所有阵列过滤?

我希望我的最终结果如下:

Array
(
    [_id] => MongoId Object
        (
            [$id] => 4f7db4dd6434e64959000000
        )

    [0] => Array
        (
            [story] => "Text of a story I posted on my wall..."
        )
    [1] => Array
        (
            [story] => "Text of a story I posted on my wall..."
        )
    [2] => Array 
        (
            [story] => "Text of a story I posted on my wall..."
            [message] => "In this case message text exists as well..."
        )
    [3] => Array
        (
            [message] => "Text of a message I posted on my wall..."
        )

    etc...
)

2 个答案:

答案 0 :(得分:2)

我认为最初的问题始于每个Feed文档的数据结构。请注意,您的对象只是一个id,然后是一个递增数量的数字键,就是这样。理想的是,您可以在顶层插入具有键和值的实际对象结构。目前,由于您直接将facebook数据直接转储到mongo而不进行格式化,因此驱动程序将您的数组映射到键/值。现在每个Feed文档都有可变数量的匿名对象。

请参阅:http://www.php.net/manual/en/mongo.writes.php

我认为您的Feed文档应该是这样的:

{ 
    "_id" : ObjectId("4f7db4dd6434e64959000000"), 
    "posts" : 
    [
        {
            "story" : "Text of a story I posted on my wall...",
            "message" : "In this case message text exists as well...",
        },
        {
            "story" : "Text of a story I posted on my wall...",
            "message" : "In this case message text exists as well...",
        }
    ],
    "posts_meta1": "some val",
    "posts_meta2": "other data"
}

请注意,它包含一个“posts”顶级键,下面是您的post对象数组。这解决了多个问题。您有一个用于索引的顶级键,而不是“数字”,您可以使用更清晰的根级别来添加更多的源字段,并且可以干净地实现查找查询。

简单的查找可能如下所示:

// Return all feed docs, and only include the posts.story field
db.feeds.find({}, {"posts.story": 1})

更高级的查询可能如下所示:

// Return an feed document that either contains a posts.story
// field, or, contains a posts.message field
db.feeds.find({
    $or: [ 
        {$exists: {"posts.story": true}}, 
        {$exists: {"posts.message": true} 
    ]
})

简而言之,从facebook返回的数据应首先格式化为对象结构,然后插入到mongo中。例如,日期应作为正确的日期对象插入,而不是原始字符串:http://www.php.net/manual/en/class.mongodate.php。这允许您在mongo中执行基于日期的查询,并且php驱动程序还将确保来回转换它们,以便它们更适合您的语言。

答案 1 :(得分:1)

如果没有看到从Facebook发送的JSON数据,很难说出story_tags字段中的结构应该是什么样子。您可能需要解码来自Facebook的JSON并强制json_decode转换为PHP关联数组:

$ar = json_decode($post['feed']['data'], true);

此处的'true'标志强制它将数据作为关联数组处理。

然后按如下方式插入:

$feeds->insert($ar);

无论哪种方式,我都倾向于在将数据存储到数据库之前将数据重组为更适合您需求的东西 - 这样您就可以更有效地使用索引。如果您确实需要存储来自Facebook的整个响应,您可以始终将其存储为嵌套对象:

$ar['raw'] = $post['feed']['data'];