<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Blog posts by Matt FitzGerald-Chamberlain</title><link href="http://world.optimizely.com" /><updated>2025-12-11T01:30:00.0000000Z</updated><id>https://world.optimizely.com/blogs/matt-fitzgerald-chamberlain/</id> <generator uri="http://world.optimizely.com" version="2.0">Optimizely World</generator> <entry><title>Data Imports in Optimizely: Part 2 - Query data efficiently</title><link href="https://www.mfcd.io/blog/data-import-part-2" /><id>&lt;p class=&quot;&quot;&gt;One of the more time consuming parts of an import is looking up data to update. Naively, it is possible to use the PageCriteriaQueryService to query a each page, one at a time as it is needed. While this does work, it can add significant overhead as it requires potentially thousands of queries.&lt;/p&gt;&lt;p class=&quot;&quot;&gt;Instead, since virtually all pages are going to need to be accessed, it is more efficient to preload all of the pages using batch APIs and then query them from the in-memory data.&lt;/p&gt;&lt;p class=&quot;&quot;&gt;The key here is using the ListContentOfContentType method of IContentModelUsage to get all of the content references using the content type, and the GetItems() method of IContentRepository to batch load items.&lt;/p&gt;





















  
  



&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var allPageRefs = _contentModelUsage
    .ListContentOfContentType(communityContentType)
    .Select(x =&amp;gt; x.ContentLink.ToReferenceWithoutVersion());

var allPages = _contentRepository
    .GetItems(allPageRefs, new LoaderOptions { LanguageLoaderOption.MasterLanguage() })
    .OfType&amp;lt;ImportedPage&amp;gt;()
    .GroupBy(x =&amp;gt; x.LegacyID)
    .ToDictionary(x =&amp;gt; x.Key, x =&amp;gt; x.First());&lt;/code&gt;&lt;/pre&gt;




  &lt;p class=&quot;&quot;&gt;Then, to load the page for editing, it’s just a matter of looking up the ID in the dictionary.&lt;/p&gt;





















  
  



&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;if (allPages.TryGetValue(importedData.Id, out var page))
{
    page = (ImportedPage)page.CreateWritableClone();
}
else
{
    page = (ImportedPage)_contentRepository.GetDefault&amp;lt;ImportedPage&amp;gt;(importFolder).CreateWritableClone();
}&lt;/code&gt;&lt;/pre&gt;




  &lt;p class=&quot;&quot;&gt;Some considerations:&lt;/p&gt;&lt;ol data-rte-list=&quot;default&quot;&gt;&lt;li&gt;&lt;p class=&quot;&quot;&gt;This can use a significant amount of memory as it is loading a potentially large segment of the database. In my testing, this can even be multiple GB of data. However, RAM is plentiful and in my testing it is well within the amount of available memory on Optimizely DXP.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p class=&quot;&quot;&gt;Loading all of the items takes a couple of seconds. However the alternative is much more. The PageCriteriaQueryService can take a significant amount of time to query each time it is used, which can add up to many minutes of additional time, just querying pages.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p class=&quot;&quot;&gt;ListContentOfContentType() may return older/other versions of content, not necessarily the latest published version. This is why in the example I stripped the version with ToReferenceWithoutVersion(). &lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;</id><updated>2025-12-11T01:30:00.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Data Imports in Optimizely: Part 3 - Only save when necessary</title><link href="https://www.mfcd.io/blog/data-import-part-3" /><id>&lt;p class=&quot;&quot;&gt;Saving to the Optimizely database is generally the most time consuming part of an import. The import can be sped up by saving as infrequently as possible.&lt;/p&gt;&lt;p class=&quot;&quot;&gt;The first time the import is run, it will be a worst case scenario as every item needs to be created in the database. However, subsequent runs where not all of the data is changing can be much faster.&lt;/p&gt;&lt;p class=&quot;&quot;&gt;The simplest option is to just check if a property is changing and only saving if it is different:&lt;/p&gt;





















  
  



&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var needsSave = false;

if (page.Title != importedData.Title) {
    page.Title = importedData.Title;
    needsSave = true;
}

if (needsSave) {
    _contentRepository.Save(page, SaveAction.Publish | SaveAction.Patch, AccessLevel.NoAccess);
}&lt;/code&gt;&lt;/pre&gt;




  &lt;p class=&quot;&quot;&gt;This can be tedious when there are dozens of properties to update. We can improve this by creating a function to perform this check for us.&lt;/p&gt;





















  
  



&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;private static void UpdateProperty&amp;lt;TPage, TProperty&amp;gt;(TPage page, string propertyName, TProperty newValue, ref bool needsSave) {
    var currentValue = page.Property[propertyName];
    
    if (currentValue != newValue) {
        page.Property[propertyName] = newValue;
        needsSave = true;
    }
}

// Update the import method
UpdateProperty(page, nameof(ImportedPage.Title), importedData.Title, ref needsSave);&lt;/code&gt;&lt;/pre&gt;</id><updated>2025-11-03T00:15:06.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Data Imports in Optimizely: Part 1 - Writing efficient data imports</title><link href="https://www.mfcd.io/blog/data-import-part-1" /><id></id><updated>2019-05-28T15:13:10.0000000Z</updated><summary type="html">Blog post</summary></entry></feed>