DEV Community

Cover image for Comparing Sitecore XP (.NET) and Sitecore XM Cloud (TypeScript): Solr vs. GraphQL for Queries
Sebastián Aliaga
Sebastián Aliaga

Posted on

Comparing Sitecore XP (.NET) and Sitecore XM Cloud (TypeScript): Solr vs. GraphQL for Queries

In the realm of Sitecore development, the shift from Sitecore XP (.NET) to Sitecore XM Cloud (TypeScript) marks a significant evolution. One of the most notable changes lies in the query mechanisms used to retrieve and manage data. While Sitecore XP relies on Solr, a powerful search platform, Sitecore XM Cloud leverages GraphQL, a modern query language for APIs. This blog will explore the differences between these two approaches, highlighting their respective benefits and drawbacks.

Sitecore XP (.NET) Overview

Sitecore XP is a comprehensive digital experience platform that uses .NET as its foundation. It provides robust content management capabilities and is known for its flexibility and extensibility. A key component of Sitecore XP is Solr, an open-source search platform used for indexing and searching content.

Sitecore XM Cloud (TypeScript) Overview

Sitecore XM Cloud represents the next generation of Sitecore, built on a headless architecture and utilizing TypeScript for development. This cloud-based platform emphasizes scalability and ease of integration with modern front-end frameworks. GraphQL plays a pivotal role in Sitecore XM Cloud, offering a powerful and flexible way to query content.

Solr in Sitecore XP

Integration with Sitecore XP: Solr is tightly integrated with Sitecore XP, acting as the backbone for content search and indexing. Developers interact with Solr through Sitecore's Content Search API.

Querying with Solr: Here's an example of a complex Solr query in Sitecore XP, including filters for template, publish date, and path, as well as faceting by author and category:

Step 1: Define the Model

First, define a model to map the search results. This model will represent the data structure returned from Solr.

public class ArticleSearchResultItem : SearchResultItem
{
    [IndexField("title")]
    public string Title { get; set; }

    [IndexField("publishDate")]
    public DateTime PublishDate { get; set; }

    [IndexField("author")]
    public string Author { get; set; }

    [IndexField("category")]
    public string Category { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Create the Controller

Next, create a controller to handle the search logic.

using System;
using System.Linq;
using System.Web.Mvc;
using Sitecore.ContentSearch;
using Sitecore.ContentSearch.Linq.Utilities;
using Sitecore.Mvc.Controllers;

public class SearchController : SitecoreController
{
    public ActionResult Articles()
    {
        using (var context = ContentSearchManager.GetIndex("sitecore_web_index").CreateSearchContext())
        {
            var query = context.GetQueryable<ArticleSearchResultItem>()
                               .Where(item => item.TemplateId == TemplateIDs.Article)
                               .Where(item => item.PublishDate >= DateTime.Now.AddMonths(-6))
                               .Where(item => item.Paths.Contains(new ID("{110D559C-39F8-42D9-8F0A-82B7A6FFFE20}"))) // Filtering by a specific path
                               .FacetOn(item => item.Author)
                               .FacetOn(item => item.Category);

            var results = query.GetResults();

            var model = new ArticleSearchViewModel
            {
                Articles = results.Hits.Select(hit => hit.Document).ToList(),
                AuthorFacets = results.Facets.Categories["author"].Values,
                CategoryFacets = results.Facets.Categories["category"].Values
            };

            return View(model);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Create the ViewModel

Create a ViewModel to pass data to the view.

using System.Collections.Generic;
using Sitecore.ContentSearch.Linq;

public class ArticleSearchViewModel
{
    public List<ArticleSearchResultItem> Articles { get; set; }
    public List<FacetValue> AuthorFacets { get; set; }
    public List<FacetValue> CategoryFacets { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Create the View

Finally, create the view to display the search results.

@model YourNamespace.ArticleSearchViewModel

<h2>Search Results</h2>

@foreach (var article in Model.Articles)
{
    <div>
        <h3>@article.Title</h3>
        <p>@article.PublishDate.ToString("yyyy-MM-dd")</p>
        <p>@article.Author</p>
        <p>@article.Category</p>
    </div>
}

<h3>Author Facets</h3>
@foreach (var facet in Model.AuthorFacets)
{
    <div>
        <p>@facet.Name (@facet.AggregateCount)</p>
    </div>
}

<h3>Category Facets</h3>
@foreach (var facet in Model.CategoryFacets)
{
    <div>
        <p>@facet.Name (@facet.AggregateCount)</p>
    </div>
}
Enter fullscreen mode Exit fullscreen mode

GraphQL in Sitecore XM Cloud

Integration with Sitecore XM Cloud: GraphQL is integrated directly into Sitecore XM Cloud, providing a unified query interface for developers. The use of GraphQL aligns well with modern JavaScript and TypeScript front-end frameworks.

Querying with GraphQL: Here's an example of a complex GraphQL query in Sitecore XM Cloud, including filters for template, publish date, and path, along with nested queries and fields for author and category:

Step 1: Define the Model

Define a TypeScript interface for the data returned from the GraphQL query.

export interface Article {
  id: string;
  name: string;
  fields: {
    title: {
      value: string;
    };
    publishDate: {
      value: string;
    };
    author: {
      value: string;
    };
    category: {
      value: string;
    };
  };
}

export interface ArticlesQueryResult {
  item: {
    id: string;
    name: string;
    children: {
      results: Article[];
    };
  };
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Create the GraphQL Query

Create the GraphQL query as a constant.

import gql from 'graphql-tag';

export const ARTICLES_QUERY = gql`
{
  item(path: "/sitecore/content/Home") {
    id
    name
    children(filter: { field: "template", value: "Article", operator: EQ }) {
      results(filter: { field: "publishDate", operator: GTE, value: "2023-01-01" }) {
        id
        name
        fields {
          title {
            value
          }
          publishDate {
            value
          }
          author {
            value
          }
          category {
            value
          }
        }
      }
    }
  }
}
`;
Enter fullscreen mode Exit fullscreen mode

Step 3: Create the Component

Create a React component to execute the GraphQL query and render the results using Apollo Client.

import React from 'react';
import { useQuery } from '@apollo/client';
import { ARTICLES_QUERY, ArticlesQueryResult } from './queries';
import { Article } from './models';

const Articles: React.FC = () => {
  const { loading, error, data } = useQuery<ArticlesQueryResult>(ARTICLES_QUERY);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  const articles = data?.item.children.results || [];

  return (
    <div>
      <h2>Search Results</h2>
      {articles.map((article: Article) => (
        <div key={article.id}>
          <h3>{article.fields.title.value}</h3>
          <p>{new Date(article.fields.publishDate.value).toLocaleDateString()}</p>
          <p>{article.fields.author.value}</p>
          <p>{article.fields.category.value}</p>
        </div>
      ))}
    </div>
  );
};

export default Articles;
Enter fullscreen mode Exit fullscreen mode

Step 4: Integrate with the Application

Integrate the Articles component into your Next.js application, typically in a page or another component.

import React from 'react';
import Articles from '../components/Articles';

const ArticlesPage: React.FC = () => {
  return (
    <div>
      <h1>Articles</h1>
      <Articles />
    </div>
  );
};

export default ArticlesPage;
Enter fullscreen mode Exit fullscreen mode

Comparison of Solr and GraphQL

Performance Considerations: Solr is optimized for complex search queries and large datasets, making it ideal for scenarios with heavy search requirements. GraphQL, on the other hand, excels in efficiency by allowing clients to request only the data they need, reducing over-fetching and under-fetching issues.

Flexibility and Ease of Use: GraphQL provides greater flexibility in querying, allowing developers to shape the response to fit their needs precisely. Solr's query syntax can be more rigid and complex, particularly for those unfamiliar with search engines.

Developer Experience: GraphQL aligns well with modern development practices and integrates seamlessly with JavaScript/TypeScript frameworks. Solr, while powerful, may present a steeper learning curve and require more specialized knowledge.

Scalability and Maintenance: Both Solr and GraphQL are scalable, but they cater to different needs. Solr is well-suited for heavy search operations, whereas GraphQL offers simplicity and efficiency for general content querying and management.

Conclusion

Both Solr and GraphQL bring unique strengths to the table in the context of Sitecore development. Solr's robust search capabilities make it a strong choice for content-heavy applications in Sitecore XP. In contrast, GraphQL's flexibility and modern approach to data querying align perfectly with the headless architecture of Sitecore XM Cloud. Ultimately, the choice between Solr and GraphQL will depend on the specific needs and goals of your project.

Top comments (0)