Sitecore Powershell Extensions- Making work easier – Part 2

Hi everyone,

Last time I had blogged about Sitecore Powershell Extensions, I had provided some easily understandable reusable code snippets which are used regularly by everyone for their small or major updating in Sitecore.

If you have not gone through that please feel free to go through the same :

https://codeandlearnspot.wordpress.com/2018/06/07/sitecore-powershell-making-work-easier-part-1/

This time I am coming with a script which I used recently to update almost 250-300 items together in easier way in a situation when we faced a critical issue.

Here is the scenario : There is a separate repository for Products and from an external third party database the products are synced and created in our Sitecore using a GUID generation algorithm. So there are about 250-300 items in our repository. But last week we found an issue where the GUID generation algorithm creates same guid for two same products in different regions if the product code is same for those two regions. So if one product was created and because of the same guid already present the other product was not getting created in Sitecore. We were not aware of this because only 5-10 items had same product codes and those were not created correctly. Now we had to create a new GUID generation logic for all the products, because the product sync happens every day and if we did not delete the old products it will create multiple products in the repository (one with old code and other with new code). Now the major issue which we faced was the Content Entry team started filling their data in these products items in almost 250 items and their data must not get lost while we delete the old products.

So we had to write a script which takes the old id product and then copy the values to the new id product. Here is that script which we used.

$logString = ""
$importRows = Import-CSV "C:\Test files\ProductData.csv"
$bulk = New-Object "Sitecore.Data.BulkUpdateContext"
$count = 1
try
{
    Write-Host "Update Process Started"
    foreach ($row in $importRows)
    {        
        $logstring = $logstring + "----------------------------------------------------------------------------------------------------------------------------------------------------------------------"
        $logstring += "`r`n"        
        $logstring = $logstring + "Item No :" +  $count
        $logstring += "`r`n"
        $oldItemId = $row.Guid
        $newItemId = $row.NewGuid        
        $logstring = $logstring + "Old Item ID : "  + $oldItemId
        $logstring += "`r`n"        
        $logstring = $logstring + "New Item ID : " + $newItemId
        $logstring += "`r`n"
        $itemList = Get-Item master: -ID $oldItemId -Language * -Version latest| Where-Object { $_.TemplateName -eq 'Product' }
        foreach($item in $itemList)
        {
            $lang = $item.Language
            $newItem = Get-Item master: -ID $newItemId -Language $lang -Version latest
            if($newItem -eq $null)
            {                
                $logstring = $logstring + "Item " + $newItemId + "not available in langauge" + $lang + "- Old Item Id" + $oldItemId
                $logstring += "`r`n"
                continue
            }
            $newItem.Editing.BeginEdit()
            $newItem.Fields["Product Description"].Value = $item.Fields["Product Description"].Value		#Description Value
            $newItem.Fields["Product Image"].Value = $item.Fields["Product Image"].Value					#Image Value
            $newItem.Fields["Premium Product"].Value = $item.Fields["Premium Product"].Value				#CheckBox value
            $newItem.Fields["Product Note"].Value = $item.Fields["Product Note"].Value						#Multilinetext value
            $newItem.Editing.EndEdit()
            $logstring = $logstring + "Product Description value is copied :" + $($newItem.Fields["Product Description"].Value) + "in language : " + $lang
            $logstring = $logstring + "Product Image value is copied :" + $($newItem.Fields["Product Image"].Value) + "in language : " + $lang
            $logstring = $logstring + "Premium Product value is copied :" + $($newItem.Fields["Premium Product"].Value) + "in language : " + $lang
            $logstring = $logstring + "Product Note value is copied :" + $($newItem.Fields["Product Note"].Value) + "in language : " + $lang
            $logstring += "`r`n"
        }
        $count++        
        $logstring = $logstring + "---------------------------------------------------------------------------------------------------------------------------------------------------------------------"
        $logstring += "`r`n"
    }
    Write-Host "Update Process Ended"
    $logstring | Out-Download -Name Logs_Product_Details_Updated.txt
}
finally
{
    $bulk.Dispose()
}

The csv which we used looks like this :

Blog powershell

So the above code actually satisfied our requirement and then downloaded the Bulk updating process details as a log file (which i have added in the code snippet by appending to a string after each step and download the same to our local system in the final step)so that we can track how many items got updated with the count also.

There might be different methods also to perform the same requirement but due to the timeline of just 1 hour in my hand, I prepared this easy and understandable code which can be reused in many ways and modified according to your requirements. So the bulk updating took about 20-25 mins for updating 250 items, so just run the code and enjoy a 20 mins of break and when you are back the process would have been completed.

Please feel free to contact me if you have any opinions, queries or suggestions on the same. You can reach me via Twitter or LinkedIn.

Till then saying goodbye to all Sitecore folks. Happy Scripting and Happy Sitecoring 🙂

 

WILDCARD MODULE – IMPLEMENTATION IN SITECORE 9 UPDATE 2

Hi everyone,

This year I start my knowledge sharing about an old but very important module, the first Wildcard module created by Adam Conn for Sitecore 6.4 and 6.5, which I used and implemented successfully in Sitecore 9.0 Update 2. Here are the links for the module and blog (if you have not used it before) :

https://marketplace.sitecore.net/en/Modules/Wildcard_module.aspx

https://community.sitecore.net/technical_blogs/b/getting_to_know_sitecore/posts/wildcards-and-data-driven-urls

This post is also a knowledge sharing and confirmation for those who have doubts or queries about this module, whether this will be supported for Sitecore latest versions etc.

So, I had a basic requirement in my project where I have a Products landing page, which shows me a list of products, and on the click of that, it should get redirected to a product detail page which is a wildcard (*) page (where the presentation details are defined). And the products which needs to be displayed are present in  a different repository, which is automatically created using an import process (and these products do not have presentation details defined).

The first step which regularly most of them does is trying to install the existing module. But the installation failed in the last step (publish:end) which gave me an error related to Sitecore Content Search index which disappointed me and then I tried to build the same module step by step from scratch.

The basic items of this module has the following content : Wildcard template, System Module Wildcard settings, Rules defined for wildcard mappings. So I created these items one by one. Now the next step is the working logic for this module. Then I extracted the dll, where I got all the basic files which I used in my foundation project that i created for wildcards.

Wldcard solution

In the Route template I added one field TreeList Ex, where we can select the template of the (*) item, so that when user requests the url, if it is the template, then redirecting it to the wildcard item. (this code logic is also managed in the WildcardProvider.cs file)

Route template.png

wildcardtempalte query.png

The old rule context was not working for me so I created new rules in the following location : “/sitecore/system/Settings/Rules/Definitions/Elements/Wildcards”

wildcard rules.png

Now there are 3 locations, where we need to setup the items and routes required for redirect.

  1. Creating token Wildcard token.png
  2. Adding position mappingProduct Mappings.png
  3. Defining routeRoutes.png

An then finally the wildcard module is ready to use. Now when we request to the (*) item and if we have mapped it to any other repository product item, Sitecore will change the context of the (*) item as product item and use the presentation details defined in the wildcard item.

As i mentioned before, I have not provided the whole implementation here, just the steps i used to migrate the old wildcard module to the new compatible one. Also this confirmed that we can reuse the wildcard module that was provided support only for Sitecore 6.4 and 6.5.

So that is all from my end today. Please feel free to contact me on LinkedIn or Twitter, if any one is planning to reuse the wildcard module and are having questions or doubts on the same.

Till then Bye Bye. Happy Sitecoring 🙂

 

Sitecore Services Client -An item with the same key has already been added

Hi everyone,

This time I am coming up with an issue we faced while using the Sitecore Services Client API. Those who are new to this topic, can please refer the below links :

Restful API for ItemService

The ItemService

Now lets get into the issue we faced. While running the following query,

https://{sitecore hostname}/sitecore/API/ssc/item/{B5E4D520-9EED-4AB2-B532-DD1A4E907AA0}/Children?database=master&includeStandardTemplateFields=false

we got a 400 status code with the description ” An item with the same key has already been added”.

400-error.png

Then we enabled the Failed Request Tracing and we could find the following information related to that error :

Failed Request Tracing

We contacted the Sitecore support and they got back to us saying the following :

Such an error might happen if the requested item has multiple fields with the same name.
This behavior is not expected and was registered as a bug in our bug tracking system.

So we checked the Item for which it was giving the following error and there it is. We had two fields in different sections having same name. Once we removed that it worked like a charm.

Sitecore also provided the reference number in case of future tracking. #207286

I hope this post would be useful for those who are facing this error while using Sitecore Service Client API.

Happy Sitecoring 🙂

 

Sitecore MVC – Bundling and Optimization

Hi everyone,

Some time before I had posted a stackoverflow question on how we can implement optimization in the blogs without using Global.asax file. After doing some research and discussion with Peter Prochazka, I am quickly writing a post on how I implemented Bundling and optimize them in my Sitecore MVC project.

All the projects will have multiple javascripts and css files so that we can maintain the readability of the code. But it also degrades the performance with the increase in load time of pages. As per definition from Microsoft : Bundling and minification improves load time by reducing the number of requests to the server and reducing the size of requested assets (such as CSS and JavaScript.).

So lets get into how we can implement bundling and optimize those bundled js or css for debugging purposes.

Add Microsoft ASP.NET Web Optimization Framework to your solution from nuget packages. You might need to install dependency packages (Microsoft.Web.Infrastructure, WebGrease, Antlr, Newtonsoft.Json). So while installing these, make sure that it does not overwrite the same Sitecore dlls (because versions differ) and there is a possibility for you to get NewtonSoft Json dependency error.

Create a folder App_Start and a BundleConfig.cs file which will have the following code logic

public class BundleConfig
{                
        [UsedImplicitly]
        public virtual void Process(PipelineArgs args)
        {
            RegisterBundles(BundleTable.Bundles);            
        }        
        public void RegisterBundles(BundleCollection bundles)
        {
            bundles.Add(new ScriptBundle("~/bundles/js").Include("~/Assets/Project/scripts/main.js"));
            bundles.Add(new StyleBundle("~/bundles/css").Include("~/Assets/Project/styles/main.css"));            
        }  
}  

Now here is the challenge. Sitecore ships with a standard Global.asax file and a lot of Sitecore developers choose to make changes directly in this to hook into application and session level events. But I prefer not to use the Global.asax file to Register the bundles, instead we can use Sitecore pipelines. The details about the Sitecore pipelines that can be used instead of the Global.asax event handlers are provided in https://laubplusco.net/global-asax-sitecore-pipelines/.

So I created an initialize pipeline and injected the BundleConfig which was created earlier

<pipelines>
      <initialize>
        <processor type="Project.Foundation.Assets.App_Start.BundleConfig, Project.Foundation.Assets" patch:before="processor[@type='Sitecore.Pipelines.Loader.ShowVersion, Sitecore.Kernel']" />
      </initialize>            
</pipelines>

In web.config set an ignore url prefix for your bundle so that Sitecore won’t try to resolve the URL to the bundle. Update setting IgnoreUrlPrefixes according to your bundle name. I have added “/bundles” in my IgnoreURlPrefixes

Render the css and js as follows in the layout fileLayout.PNG

So now the js and css files are now bundled and you can see them in your website source code as followsBundled output

Next what if you need to optimize those bundles. You can do it in different ways :
As Peter Prochazka had suggested to me, creating a settings item and calling it from the Bundle Config. But here the problem is every time you make a change to the config, it need to have Sitecore restarted again and again.
So again I chose to inject using pipelines. Also the optimization is usually done from the Application_Start method of Global asax. So as we chose to use pipelines, we use the PreprocessRequest/HttpRequestBegin of the Sitecore pipelines. And here i chose to add in the end of the preprocessrequest pipeline
Now what if you need to optimize the bundles using a query string? (You can find the example in https://www.bugdebugzone.com/2015/07/bundling-and-minification-in-sitecore.html

For this you can create a class which inherits from PreprocessRequestProcessor and write the code logic for Optimization and then add the class to the pipeline as follows :

public class BundleOptimizations : PreprocessRequestProcessor
{
        public override void Process(PreprocessRequestArgs args)
        {            
            EnableOptimizations();
        }       

        public static void EnableOptimizations()
        {
            var debugMode = HttpContext.Current.Request.QueryString["debug"];
            if (!string.IsNullOrEmpty(debugMode) && string.Equals(debugMode, "true", StringComparison.InvariantCultureIgnoreCase))
            {
                BundleTable.EnableOptimizations = false;
            }
            else
            {
                BundleTable.EnableOptimizations = true;
            }

        }
}

Then adding it into the preprocessrequest

<preprocessRequest>
        <processor type="Project.Foundation.Assets.App_Start.BundleOptimizations, Project.Foundation.Assets" />
</preprocessRequest>

 

We can add the same using HttpRequestBegin also, but when I created it what I noticed was, when we are adding the processor to the end of the HttpRequest pipeline, it is not getting implemented as expected. The optimization is not happening. Then i tried to put it on top of the HttpRequestBegin pipeline and it works. But since I had my confusions, I preferred to implement the same at the end of preprocessrequest pipeline

Also the one more reason why I chose the PreprocessRequest pipeline is while  I was going through the showconifg, I could see the FXM bundle was registered in the PreProcessRequest pipeline  :

FXM bundles

Now if you browse your URL with ?debug=true, for example, if the URL is http://www.example.local?debug=true, then you can see the following output in the source

optimizedoutput

And there it is!!! The scripts are de-optimized so that you can debug it in your website.

This was just my method for implementing Bundling and Optimization in your Sitecore MVC project. There are many other methods also without using pipelines and just using Global.asax, without optimizing etc.

Feel free to share your thoughts on this.

Till then Bye. Happy Sitecoring !!! 🙂

MODIFYING FIELD VALUE – SHARED, VERSIONED – DATABASE GET CORRUPTED

Hi everyone,

This time I am coming up with a small but major issue which troubled us for long time.

Here is the brief description of the issue :

When our Content Authors were editing an item (Example : Country) and they were modifying its address field value. Suddenly the authors reported saying the item is not reflecting in the live website even after they published, republished etc.
We thought the issue might be with the publishing not running as expected or the cache not getting cleared after publishing.
But those were not the issue, We tried many methods, clearing cache, publishing again and again, deleting the item and creating new item and publishing , still we could not find out what caused the issue.

Then we came across a parameter that was changed recently for the item in the template. In the template, the field for address was actually versioned at first, and then it was made to shared and then for some purpose again the field was made to versioned.

shared1                  Versioned

Now the field is finally made to be Versioned (unchecking the shared checkbox means the value is not shared)

So we executed the following query in both the dbo.SharedFields and dbo.VersionedFields tables in the master database.

SELECT * FROM [dbo].[SharedFields] where ItemId = ‘xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx’ and FieldId = ‘yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy’
SELECT * FROM [dbo].[VersionedFields] where ItemId = ‘xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx’ and FieldId = ‘yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy’

Here xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx gives the Item ID which you are facing the issue and yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy gives the ID of the field (you can get it from the template) which has the issue.

Surprisingly we could see the same result in both the tables dbo.SharedFields and dbo.VersionedFields. The expected result should be the result should occur only in the dbo.VersionedFields table only.

So after investigating, we could see from the following article : https://kb.sitecore.net/articles/045873

When changing the value of the Shared or Unversioned property of a particular field, every item based on the modified template is updated and the corresponding field values are moved to the appropriate data table in the Sitecore database – SharedFields, UnversionedFields, or VersionedFields.

However, in situations when the field sharing properties on a template are changed as part of a package installation, related items may not be updated properly, and corresponding field values may be located in different Sitecore database tables.

In this case, an author may experience various issues when working with items.

For example, field values may not be changed as expected upon save operation, or the data may not be published in an expected manner.

In the article they also have mentioned a fix, which installs a dll and a config and through which they run a process from FixFieldSharing.aspx.
But here the problem is like it will run for entire database and takes too much time. Also as they have mentioned, it may cause data loss in the items affected by changing field sharing properties.

So we had the issue only in one or two items and fields, so we did not run the fix suggested by Sitecore. Instead went to the template and changed the value to shared once (waited for some time so that the Sitecore background process finishes) and then again changed back to versioned (and waited till that operation finished).
Actually the issue occurs because, whenever we changed the field value to shared or versioned, Sitecore runs a background job which might have not executed properly which caused the data to be corrupted.

Hurray !!!. We have fixed that big issue which troubled us for almost a month in within 1 hour. Then we published the item (also with the templates as it had changed the field values) and then it was successfully published.

Next time I will meet you with different post. Until then Bye Bye!!!

Follow me on Twitter and Linkedin for more Sitecore related updates and shares (About)

Happy Sitecoring!

Campaign Creator – Issue while creating and loading campaigns

Hi everyone,

Today I am here to share an issue which we faced while creating and loading campaigns.

We are using Sitecore 8.2 Update 3 instance and we started to use the Campaign Creator option, very recently and that’s when we noticed about these issues.

Here is the description of the issue :

When a user is trying to create a campaign from Campaign creator, we are getting the following error.
campaign 1

But the campaigns can be viewed from the Marketing Control panel.
campaign 2

When the campaign creator dashboard is loading in the startup, it must display the list of campaigns that are created and deployed. But it is showing ”No campaign activities found”.
campaign 3

In the logs, the following error was shown :

Exception System.ArgumentException: the definition was not found: {3288EF08-CC53-45E6-9804-29DD1B397695}
Parameter name: definitionId
at Sitecore.Diagnostics.Assert.ArgumentCondition(Boolean condition, String argumentName, String message)
at Sitecore.Marketing.Definitions.DefinitionManagerBase`1.<>c__DisplayClass5`1.<Activate>b__0()
at Sitecore.Marketing.Core.IgnoreRecursiveCalls.Run(ID id, Action action)
at Sitecore.Marketing.Definitions.DefinitionManagerBase`1.Activate[TRecord](ID definitionId, IDefinitionRepository`1 repository, Func`2 toDefinition)
at Sitecore.Marketing.Definitions.Campaigns.CampaignDefinitionManager.ActivateAsync(ID definitionId)
at Sitecore.Marketing.Definitions.DefinitionManagerBase`1.Save[TRecord](TDefinition definition, Boolean activate, IDefinitionRepository`1 repository, Action`2 setCustomFields)
at Sitecore.Marketing.Definitions.Campaigns.CampaignDefinitionManager.SaveAsync(ICampaignActivityDefinition definition, Boolean activate)
at Sitecore.Marketing.Definitions.DefinitionManagerBase`1.Save(TDefinition definition, Boolean activate)
at Sitecore.Marketing.Campaigns.Services.Data.CampaignRepository.Add(CampaignEntity entity)
at Sitecore.Services.Infrastructure.Services.EntityServiceBase`1.CreateEntity(T entity)
at lambda_method(Closure , Object , Object[] )
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters)
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)
— End of stack trace from previous location where exception was thrown —
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()

We contacted Sitecore support for the issue, and after some analysis they got back to us with the following findings :

The issue was related to the fact that we were using Publishing Service module (2.0) in our instance. And also it is specified in the installation guide of the Sitecore Publishing Service that, the “content availability” feature must be turned off in CM server and should be turned on only on CD.

https://dev.sitecore.net/~/media/6A0A9E06FBD549059473643F4ADE19DB.ashx

The “Sitecore.Publishing.Service.Delivery.ContentSearch.ApplyGlobalAvailabilityLinqFilters, Sitecore.Publishing.Service.Delivery” processor from the “Sitecore.Publishing.Service.ContentAvailability.config” file breaks search on CM server and causes Campaign Creator to show empty dashboard page. Also the issue with the saving new campaign activity, is also related to the “content availability” feature and is caused by “filterItems” and “enableWorkflow” settings enabled in Sitecore.Publishing.Service.ContentAvailability.config configuration file.

We had enabled this feature that the CM server also should act as CD server for the content availablity for some purpose.

Campaign_Contentavailability

But as Sitecore suggested we disabled the “content availability” feature from the CM servers and BINGO!!! Both the issues which we mentioned were solved. Now we were able to create new campaigns and also see them in the dashboard.
But now, when the campaign dashboard was loading, it was showing only the newly created campaigns. But there were some default campaigns (Ex : Social) that are present in Sitecore and also some campaigns that are already created through our Marketing Control Panel under a folder , which were not getting displayed in the Campaign list. For solving this issue we have performed a rebuild of “sitecore_marketingdefinitions_master” and now all the campaigns are shown including the default ones.

rebuild marketing definitions

This was an implementation issue which occurred from our side, where we did not disable the “content availability” feature from the CM servers. I guess many other people also usually faces these kind of implementing issues and the main aim of this post was to notify everyone to implement the features/modules in Sitecore as per the installation guide and make sure that you disable/enable the configs listed as per the installation guide/Config Enable Disable Excel spreadsheet in both CM and CD servers.

Hope you enjoyed this post.

Will meet you all soom with a new issue or implementation.

Till then Bye. Happy Sitecoring!!!

Querying Sitecore Forms DB – Sitecore xDB Mongo Database

Hi all,

Welcome to my post on Querying Sitecore Forms collection in the xDB – Mongo Database.

MongoDB collection database is an important part of a Sitecore Experience Database (xDB) that allows the companies/organizations to collect all of their customer interactions/data from all channels that allows marketers to better optimize the customer experience in real-time. In xDB, the collection database acts as a central repository for storing contact, device, interaction, history and automation data.

Suppose we have created a form using WFFM and a user is submitting the form. If the form is submitted successfully, the Form Reports can be accessed from the “Form Reports” tab, when we click on a form in Sitecore. The same data is also saved in the MongoDB collection named “FormData” under the analytics database.

Screenshot 1

We all might face an issue with the the form that the email messages received is not same as the data shown in the Form Reports. For example, if there is an event form, and the event coordinator gets 50 emails as registered and when they check the form reports it shows only 45. Unless we go to the database directly and check the data, we are not able to confirm the issue. Also if we need to confirm whether a particular email id value is saved in the database.

So we can check some examples on how to query the MongoDB database using 2 tools : Robo 3T and Studio 3T (both are tools provided by formerly used tool Robomongo)

You can download the tool from https://robomongo.org/

Robo3T is used just by the MongoDB enthusiasists, who are interested just in querying the database and playing around the data using differnt queries.
Studio 3T is used mainly by the professionals and it provides following advantages :
1. Fully featured IDE with embedded shell
2. Visual Query Builder
3. In-Place editing
4. IntelliShell with Auto-Completion
5. Query MongoDB with SQL
6. Export to / import from SQL DB
7. Export to csv

There are three encoding supported for Legacy UUID subtype 3:

Legacy Java Encoding, Legacy .NET Encoding, Legacy Python Encoding

By default, when we open a collection, it opens the Raw data without any encoding. For understanding and easy querying, we use .NET encoding. We can select .NET encoding (in Robo 3T) by Navigating to Options -> Legacy UUID Encoding -> Use .NET Encoding

Screenshot 2

Now i will get on to how we can query the FormData. For that first we need to take the ID of the form where the issue is getting reflected.

The item ID of the form which we have used is {8E08E97B-0D58-4988-87CE-F5D354ECFC30}. This is the same ID which we use with querying with the NUUID.

1. To get all the records from the Form Data collection:

db.getCollection('FormData').find({"FormID":NUUID("8e08e97b-0d58-4988-87ce-f5d354ecfc30")})

This query gives the following results :

Screenshot 3

2. To get a particular value of any field of the form – Suppose i have a field called First Name and the value i have given is “Test”. Here is how we query it :

db.getCollection('FormData').find({"FormID":NUUID("8e08e97b-0d58-4988-87ce-f5d354ecfc30"),"Fields.Value":"Test"})

Screenshot 4

But here we get three different results which has the same Name : “Test”

3. Now lets choose an unique identifier (Email ID) so that i get a particular formdata which has FirstName as “Test” and Email ID as “test@test.com” . Here we get this using “AND” query.

db.getCollection('FormData').find({$and : [ {"FormID":NUUID("8e08e97b-0d58-4988-87ce-f5d354ecfc30")},{"Fields.Value":"test@test.com"}, {"Fields.Value":"Test"}]})

Screenshot 5

Here is the result when there is requirement to find whether the user with name “Test” and email ID “test@test.com” has submitted the form.

These were just very few examples on how to get forms data via querying through MongoDB. In similar way we can also query Interactions, Contact collections also to get more details on the Visitor data (Page count, Time, Browser, Site Name etc)
More details on the querying is provided in the series of blogs written by Brijesh Patel : https://horizontalintegration.blog/2017/01/22/query-sitecore-xdb-mongodatabases-part-1/

In my next blog, I will explain on how to query using Studio 3T, using Visual Query Builder, Importing the data to csv or excel. If you have any queries or doubts, please feel free to contact me.

Till then Bye Bye ! Happy Querying