[ SOLVED ] Examine: Exact Node Name only?
# help-with-umbraco
j
Hi! Following on from yesterday's [exciting post](https://discord.com/channels/869656431308189746/1151193112228659261) I'm back with another Examine question. Is there a way to specify "Search for exactly this NodeName, don't return anything else unless it's exactly the same"? Found that searching "Article" would also give nodeNames like "Article About Umbraco" - which, while handy, isn't ideal for the use case of checking if a node called "Article" currently exists. Code as is - goal is to only get a node with the NodeName as an exact match. To this end I've now added the extra if/foreach validation against the search result's "AllValues" dict, which feels cursed to say the least.
Copy code
var folderSearchResult = index
    .Searcher
    .CreateQuery(Umbraco.Cms.Infrastructure.Examine.IndexTypes.Media)
    .NodeTypeAlias(Folder.ModelTypeAlias)
    .And()
    .NodeName(nameOfFolder)
    .And()
    .ParentId(rootFolderId)
    .Execute();

if (folderSearchResult != null)
{
    foreach (var folderResult in folderSearchResult)
    {
        var nodeName = folderResult.AllValues["nodeName"].FirstOrDefault();
        if (nodeName != null && nodeName.Equals(nameOfFolder))
        {
            return int.Parse(folderResult.Id);
        }
    }
}
TIA!
j
This is to do with how nodeName is indexed, you can't do an exact match against it because examine/lucene doesn't actually know what that field says - it sees a tokenized list of what's inside it. Just to check - what 's this for and how reliable does it need to be? This seems like a very specific use case for a "search" and since you already know the parent id, fetching what you need straight out of the cache may be both simpler and safer.
j
Hi Jason, thanks for your reply. Specific case: - I'm migrating blog articles where each blog article is made up of a folder, containing a markdown file (the blog's content) and an image (the hero image for the blog) - I'm running this migration by looping over the blog folders and creating through ContentService - For each of these blog folders I'm wanting to create a folder in Media, under the folder "Blog", with the name of the blog (i.e. ~/Blog/BlogName/) - Before creating the Media folders I want to check whether that specific folder (~/Blog/BlogName/) exists - essentially a GetOrSet action for that specific folder So in this instance, the "search" has to be exact - if it's a case of instead querying mediaService instead of Examine then cool, I'm just getting used to when to use which type of search and for what. Does that make sense? Would appreciate your input. TIA!
My attempt through querying the cache w UmbracoHelper is this:
Copy code
csharp
public IPublishedContent? GetBlogArticleFolder()
{
    var rootFolder = UmbracoHelper.MediaAtRoot().FirstOrDefault(x => x is { Name: "Blog", ContentType: Folder.GetModelContentType(_publishedSnapshotAccessor) });

    return rootFolder?.Descendants<Folder>().FirstOrDefault(x => x.Name is "Article Name To Find");
}
Would this be the correct way to find the child of a media item called "Blog" which is a folder called "BlogName"?
s
So: - Examine - tokenized search - UmbracoHelper - querying against cache (note: for Content, items have to be published first, media items are always in a published state) - Content/MediaService - querying against the db directly (when looking for content that is not yet published / the version you need is in draft) And your code looks correct 👍 Ps. did you know if you write
csharp
after the first 3 backticks you get nice code highlighting? 😁
j
Brilliant, thank you on all counts!
j
Nice, I always forget about
is
n
Examine can do exact matches, the index and query time analysers for the field do need to not do any stemming etc. Raw field type.
m
there is phrase matching in examine too.. though note the indexer stores as lower case.
Copy code
csharp
.CreateQuery(Umbraco.Cms.Infrastructure.Examine.IndexTypes.Media)
    .NodeTypeAlias(Folder.ModelTypeAlias)
    .And()
    .NodeName(nameOfFolder.ToLower().Escape())
    .And()
    .ParentId(rootFolderId)
    .Execute();
if you look at the query generated from
.Field("someField", "Article Name To Find")
it actually ends up being somefield is "article" or "name" or "to" or "find" due the the fluent examine parsing? or just examine itself nodeName is already a raw field I think so
Escape()
should work for the phrase matching but if you needed it for other fields..
note changing the config, you need to rebuild the indexes for it to take effect.
j
nodeName
isn't a raw @Mike Chambers In the case of two nodes: 1: "Page" 2: "Another Page"
NodeName("page".Escape())
will return both. Adding other/extra raw fields though is a great way to look up things like product SKUs, exact name etc. or pulling content from anywhere on the tree based on a property value (you can actually mimic one-to-many/one relationships using examine to do a reverse lookup, which is really cool.)
m
oops.. for some reason I was thinking of NodeTypeAlias but reading NodeName.. and yep caveats to phrase matching.. could you use the
urlName
, or does
another-page
still get tokenised with - as a delimeter?
j
Unfortunately yes, it's tokenized.
a
hello, in umbraco 10 - im usyng examine searcher and i have lists without tamplate that i wont to showing the ancestors that contain the lists. its important to say im using the lists ad blockList and inside choosing picker to chose those Lists. is there any way to do that with examine searcher?
7 Views