Search code examples
phpsolrsolarium

Solarium for Solr - Nested Documents


I'm using Solr 9.4.1, with Solarium 6.3.5. Reading through the docs I think I'm coding the implementation correctly, but my documents are not created in Solr as a parent/child relationship. Does it not work that way, and I need to change my search criteria to work with a flat array? I do see in Solr, all records have a root key, and in the case of a parent record it matches its own id, while child records match their parent. But that's the only reference telling me this worked.

Here's my code, hopefully someone that understands Solr/Solarium better than I can see the issue.

public function syncForum()
    {
        $client = $this->solrclient;
        $update = $client->createUpdate();

        $db = db_connect();
        // Create arrays to store topic and comment documents
        $topicQuery = $db->query("SELECT
                            forum_topics.id AS topic_id,
                            forum_topics.topic_subject AS topic_subject,
                            forum_topics.topic_message AS topic_message,
                            forum_topics.created_at AS created_at,
                            forum_categories.title AS forum_category,
                            users.username AS topic_author
                        FROM
                            forum_topics
                        INNER JOIN forum_posts ON forum_posts.post_topic = forum_topics.id
                        LEFT JOIN users ON users.id = forum_posts.post_by
                        LEFT JOIN forum_categories ON forum_categories.id = forum_topics.topic_cat");
        $topicResult = $topicQuery->getResultArray();

        $documentArray = [];
        foreach ($topicResult as &$topic) {

            //Loop through topics and create a topic document
            $document = $update->createDocument();
            $document->id = $topic['topic_id'];
            $document->topic_subject = $topic['topic_subject'];
            $document->topic_message = $topic['topic_message'];
            $document->category = $topic['forum_category'];
            $document->author = $topic['topic_author'];
            // $document->_root_ = 'true';

            $topicDate = $topic['created_at'];
            $dateTime = new \DateTime($topicDate);
            $document->created_at = $dateTime->format("Y-m-d\TH:i:s\Z");

            $documentArray[] = $document;

            //For each topic, loop through the comments and create a comment document
            $commentQuery = $db->query("SELECT forum_posts.id, forum_posts.post_content AS comment_message, forum_posts.created_at, users.username AS author
                                 FROM forum_posts 
                                 LEFT JOIN users ON users.id = forum_posts.post_by
                                 WHERE post_topic =" . $topic['topic_id']);
            $comments = $commentQuery->getResultArray();

            $commArray = [];
            foreach ($comments as $i => $comment) {

                $commArray[$i]['id'] = $comment['id'];
                $commArray[$i]['comment_message'] = $comment['comment_message'];
                $commArray[$i]['author'] = $comment['author'];

                $originalDate = $comment['created_at'];
                $dateTime = new \DateTime($originalDate);
                $formattedDate = $dateTime->format("Y-m-d\TH:i:s\Z");

                $commArray[$i]['created_at'] = $formattedDate;
            }
            $document->childdocs = $commArray;
        }

        // add the documents and a commit command to the update query
        $update->addDocuments($documentArray);
        $update->addCommit();

        // this executes the query and returns the result
        $result = $client->update($update);
        // Output status information
        echo "Status: " . $result->getStatus() . " | Query Time: " . $result->getQueryTime() . PHP_EOL;
    }

Solution

  • Note the field you are using childdocs is a "pseudo-field" (ie. not an actual field in the documents), and thus, by default, the matching documents of a search query won't include any of their nested children in the response.

    To enrich results with the documents' descendants you need to use the Child Doc Transformer by adding [child] to the field list parameter, eg. fl=*,[child]. You might also need to add the _nest_path_ field to the schema (for the transformer) to enable more features.