{"id":26681336,"url":"https://github.com/callumbwhyte/umbraco-search-extensions","last_synced_at":"2026-03-10T05:07:47.063Z","repository":{"id":47546704,"uuid":"274514651","full_name":"callumbwhyte/umbraco-search-extensions","owner":"callumbwhyte","description":"Extensions for performing searches in Umbraco","archived":false,"fork":false,"pushed_at":"2024-06-07T08:27:00.000Z","size":157,"stargazers_count":26,"open_issues_count":4,"forks_count":13,"subscribers_count":2,"default_branch":"dev","last_synced_at":"2025-03-26T07:15:18.513Z","etag":null,"topics":["dotnet","examine","hacktoberfest","lucene","search","search-engine","umbraco"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/callumbwhyte.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-06-23T21:42:13.000Z","updated_at":"2024-09-18T08:20:13.000Z","dependencies_parsed_at":"2024-11-18T22:02:59.944Z","dependency_job_id":"33a89b1d-4cf0-4c0d-ba1c-4ae52e96a833","html_url":"https://github.com/callumbwhyte/umbraco-search-extensions","commit_stats":{"total_commits":65,"total_committers":5,"mean_commits":13.0,"dds":0.06153846153846154,"last_synced_commit":"06c38f5808b5345c241e8bfafbcdab982d7658ad"},"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/callumbwhyte%2Fumbraco-search-extensions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/callumbwhyte%2Fumbraco-search-extensions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/callumbwhyte%2Fumbraco-search-extensions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/callumbwhyte%2Fumbraco-search-extensions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/callumbwhyte","download_url":"https://codeload.github.com/callumbwhyte/umbraco-search-extensions/tar.gz/refs/heads/dev","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248567069,"owners_count":21125782,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dotnet","examine","hacktoberfest","lucene","search","search-engine","umbraco"],"created_at":"2025-03-26T07:15:24.135Z","updated_at":"2026-03-10T05:07:42.014Z","avatar_url":"https://github.com/callumbwhyte.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Umbraco Search Extensions\n\n\u003cimg src=\"docs/img/logo.png?raw=true\" alt=\"Umbraco Search Extensions\" width=\"250\" align=\"right\" /\u003e\n\n[![NuGet release](https://img.shields.io/nuget/v/Our.Umbraco.Extensions.Search.svg)](https://www.nuget.org/packages/Our.Umbraco.Extensions.Search/)\n\n## Getting started\n\nThis package is supported on Umbraco v9-v13 and v14\n\n### Installation\n\nSearch Extensions is available via [NuGet](https://www.nuget.org/packages/Our.Umbraco.Extensions.Search/).\n\nTo install with the .NET CLI, run the following command:\n\n    $ dotnet add package Our.Umbraco.Extensions.Search\n\nTo install from within Visual Studio, use the NuGet Package Manager UI or run the following command:\n\n    PM\u003e Install-Package Our.Umbraco.Extensions.Search\n\n## Usage\n\n### Querying\n\nThere are several short-hand extension methods for querying Umbraco content in an index – checking if an item is published, is visible, or has a template.\n\nQuerying only published content items can be done like this:\n\n```\nquery.And().IsPublished()\n```\n\nSimilarly, querying all content where the `umbracoNaviHide` property is **not** set can be done like this:\n\n```\nquery.And().IsVisible()\n```\n\nIt is possible to query content with a specific template ID set. If `0` or no value is passed to the method, the query will match content with **any** templatee ID set.\n\n```\nquery.And().HasTemplate(int templateId)\n```\n\nFinally, it is possible to query for content that has **any** one of the specified content type aliases. Out of the box Umbraco supports querying for a single content alias.\n\n```\nquery.And().NodeTypeAlias(string[] aliases)\n```\n\n### Cultures\n\nUmbraco properties that have been set to \"vary by culture\" are indexed with a specific alias: `{fieldName}_{culture}`. For example, if the \"pageTitle\" field varies by culture and has 2 languages, English and Spanish, the index would contain 2 fields: `pageTitle_en` and `pageTitle_es`.\n\nA culture can be passed to `Field` and `NodeName` queries like this:\n\n```\nquery.And().Field(string field, string culture)\n\nquery.And().NodeName(string nodeName, string culture)\n```\n\nIt even works with grouped queries such as `GroupedAnd`, `GroupedOr`, and `GroupedNot`, where multiple fields can be specified:\n\n```\nquery.And().GroupedOr(string[] fields, string culture)\n```\n\n### Searching\n\nThe `Page\u003cT\u003e` extension methods efficiently get a given number of items *(`perPage`)* at a specific position *(`page`)* from Examine's `ISearchResults`. An optional type constraint can be added to also return paged results cast to `IPublishedContent`.\n\n```\nvar query = searcher.CreatePublishedQuery();\n\nvar searchResults = query.Execute();\n\nvar results = searchResults.Page\u003cT\u003e(query, int page, int perPage, out int totalPages, out int totalResults);\n```\n\nThe total number of pages and results are exposed as an `out` parameter, but can be disgarded if not needed like so:\n\n```\nsearchResults.Page\u003cT\u003e(query, int page, int perPage, out _, out _);\n```\n\n### Results\n\nAn entire results collection can be cast to a list of a given type like this:\n\n```\nvar results = query.Execute().GetResults\u003cT\u003e();\n```\n\nSpecific fields from an individual search result can be accessed via the `.Value\u003cT\u003e()` extension method like this:\n\n```\nforeach (var result in query.Execute())\n{\n    var value = result.Value\u003cT\u003e(string field);\n}\n```\n\n### Advanced fields\n\nSearch Extensions introduces several new field types into Examine – `json`, `list`, `UDI` and `picker` – to ensure Umbraco data is correctly indexed and queryable.\n\nExamine allows controlling an index's fields, field types, and [more](https://shazwazza.github.io/Examine/configuration#iconfigurenamedoptions), via [.NET's Named Options pattern](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options):\n\n```\npublic class ConfigureIndexOptions : IConfigureNamedOptions\u003cLuceneDirectoryIndexOptions\u003e\n{\n    public void Configure(string name, LuceneDirectoryIndexOptions options)\n    {\n        if (name == \"ExternalIndex\")\n        {\n            options.FieldDefinitions.AddOrUpdate(new FieldDefinition(\"fieldName\", \"fieldType\"));\n        }\n    }\n}\n```\n\nThe options class must be registered in the [Dependency Injection](https://our.umbraco.com/documentation/reference/using-ioc/) container to apply:\n\n```\nbuilder.Services.ConfigureOptions\u003cConfigureIndexOptions\u003e();\n```\n\n#### Core fields\n\nUmbraco's \"path\" field is automatically indexed as a list and so a content item with the path `-1,1050,1100` can be queried like this:\n\n```\nquery.Field(\"path\", \"1100\");\n```\n\nUmbraco's \"createDate\" and \"updateDate\" fields are automatically indexed as `date` values, whereas they would be regularly indexed as string values.\n\n#### Pickers\n\nThe `picker` field type adds search-friendly aliases for the picked items into the index.\n\nA picker with a selected a content item called \"Example Page\" can be queried like this:\n\n```\nquery.Field(\"somePicker\", \"example-page\");\n```\n\n#### JSON\n\nThe `json` field type splits the properties of a JSON object into individual fields within the index.\n\nImagine a field called \"locations\" has the following JSON value:\n\n```\n[\n    {\n        \"city\": \"London\",\n        \"position\": {\n            \"latitude\": 51.5074,\n            \"longitude\": 0.1278\n        }\n    },\n    {\n        \"city\": \"New York\",\n        \"position\": {\n            \"latitude\": 40.7128,\n            \"longitude\": 74.0060\n        }\n    }\n]\n```\n\nEach property will be created as a field in the index, including any nested properties. In this example these would be called \"locations_city\", \"locations_position_latitude\" and \"locations_position_longitude\".\n\nIt is possible to index a subset of a JSON object's properties by supplying a path in [JSON Path format](https://www.newtonsoft.com/json/help/html/QueryJsonSelectTokenJsonPath.htm).\n\nRegister a new `ValueTypeFactory` in the index implementing the `json` type, and define the path as a parameter, before assigning it to a field:\n\n```\npublic class ConfigureIndexOptions : IConfigureNamedOptions\u003cLuceneDirectoryIndexOptions\u003e\n{\n    public void Configure(string name, LuceneDirectoryIndexOptions options)\n    {\n        if (name == \"ExternalIndex\")\n        {\n            options.IndexValueTypesFactory = new Dictionary\u003cstring, IFieldValueTypeFactory\u003e(options.IndexValueTypesFactory)\n            {\n                [\"position\"] = new DelegateFieldValueTypeFactory(fieldName =\u003e\n                {\n                    return new JsonValueType(fieldName, \"$[*].position\");\n                };\n            };\n\n            options.FieldDefinitions.AddOrUpdate(new FieldDefinition(\"locations\", \"position\"));\n        }\n    }\n}\n```\n\n#### Multiple field types\n\nThere are advanced cases where indexing a value as multiple field types might be necessary, such as indexing different parts of the same JSON object into separately named fields or indexing specific properties within a JSON object as a defined type.\n\nThe `MultipleValueTypeFactory` assigns a chain of field types to a field and applies them in sequence:\n\n```\npublic class ConfigureIndexOptions : IConfigureNamedOptions\u003cLuceneDirectoryIndexOptions\u003e\n{\n    public void Configure(string name, LuceneDirectoryIndexOptions options)\n    {\n        if (name == \"ExternalIndex\")\n        {\n            options.IndexValueTypesFactory = new Dictionary\u003cstring, IFieldValueTypeFactory\u003e(options.IndexValueTypesFactory)\n            {\n                [\"locationData\"] = new DelegateFieldValueTypeFactory(fieldName =\u003e\n                {\n                    return new MultipleValueTypeFactory(\n                        fieldName,\n                        new IIndexFieldValueType[]\n                        {\n                            new JsonValueType(x, \"$[*].city\"),\n                            new JsonValueType(\"position\", \"$[*].position\")\n                        }\n                    );\n                };\n            };\n\n            options.FieldDefinitions.AddOrUpdate(new FieldDefinition(\"locations\", \"locationData\"));\n        }\n    }\n}\n```\n\nIn this example, the same \"locations\" JSON object will include all cities while an entirely new \"position\" field will be created including all latitudes and longitudes.\n\n## Contribution guidelines\n\nTo raise a new bug, create an issue on the GitHub repository. To fix a bug or add new features, fork the repository and send a pull request with your changes. Feel free to add ideas to the repository's issues list if you would to discuss anything related to the library.\n\n### Who do I talk to?\n\nThis project is maintained by [Callum Whyte](https://callumwhyte.com/) and contributors. If you have any questions about the project please get in touch on [Twitter](https://twitter.com/callumbwhyte), or by raising an issue on GitHub.\n\n## Credits\n\nThe package logo uses the [Magnifying Glass](https://thenounproject.com/term/search/74453/) icon from the [Noun Project](https://thenounproject.com/) by [Rohith M S](https://thenounproject.com/rohithdezinr/), licensed under [CC BY 3.0 US](https://creativecommons.org/licenses/by/3.0/us/).\n\n### A special #h5yr to our contributors\n\n* [Busra Sengul](https://github.com/busrasengul)\n* [Chriztian Steinmeier](https://github.com/greystate)\n* [Dave Woestenborghs](https://github.com/dawoe)\n* [Gareth Wright](https://github.com/garpunkal)\n* [Jonas Pyfferoen](https://github.com/kows)\n\n## License\n\nCopyright \u0026copy; 2024 [Callum Whyte](https://callumwhyte.com/), and other contributors\n\nLicensed under the [MIT License](LICENSE.md).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcallumbwhyte%2Fumbraco-search-extensions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcallumbwhyte%2Fumbraco-search-extensions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcallumbwhyte%2Fumbraco-search-extensions/lists"}