CRUD Operation using Elastic Search And .Net Core API

Introduction

In this article, I will demonstrate CRUD operations using elasticsearch and the.net core API. Here I will take an example that will help us understand how to insert, update, read, and delete documents by a parameter in elastic search.  I have also covered UpdateByQueryAsync to update and DeleteByQuery to delete the elastic documents.

How do you set up an elastic search in your development system? You can refer to my previous article. Getting Started With Elastic In Using .NET Nest Client.

Here I will create a window console application using.NET Core. Using this application, I will explain CRUD operations with elastic search and the web API. I will test my crud operation using the Swagger UI. Let's start with step-by-step explanations. First, I will explain how to add an elastic client to the start-up file.

 public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();

            // Configure elastic search URI and default index
            var node = new Uri("http://localhost:9200");
            var settings = new ConnectionSettings(node);
            settings.DefaultIndex("products");

            // Add elstic cliend dependency
            var client = new ElasticClient(settings);
            services.AddSingleton<IElasticClient>(client);

            // Add product service dependency
            services.AddScoped<IProductService, ProductService>();

            //Enable swagger here
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "ElasticSearchWebApi", Version = "v1" });
            });
        }

In the start-up class, I added elastic client, swagger, and dependency for the product service.

Let's create a model for our example, which we will use to create, read, update, and delete documents using elastic search.

public class Product
    {
        public int ProductId { get; set; }
        public string ProductName { get; set; }
        public string ProductDescription { get; set; }
        public decimal Price { get; set; }
        public DateTime LaunchDate { get; set; }
        public string Category { get; set; }
    }

Let's create a product service interface and a product service class.

 public interface IProductService
    {
        Product AddProduct(Product product);
        List<Product> GetAllProducts();
        Product GetProductById(int productId);
        void UpdateProduct(Product product);
        void DeleteProduct(int productId);

    }
    public class ProductService : IProductService
    {
        public readonly IElasticClient _elasticClient;

        public ProductService(IElasticClient elasticClient)
        {
            _elasticClient = elasticClient;
        }

        public Product AddProduct(Product product)
        {
            var response = _elasticClient.IndexDocument(product);

            if (response.IsValid)
            {
                return product;
            }
            else
            {
                return new Product();
            }
        }

        public void DeleteProduct(int productId)
        {
            _elasticClient.DeleteByQuery<Product>(p => p.Query(q1 => q1
                             .Match(m => m
                                 .Field(f => f.ProductId)
                                 .Query(productId.ToString()
                                 )
                         )));
        }

        public List<Product> GetAllProducts()
        {
            var esResponse = _elasticClient.Search<Product>().Documents;

            return esResponse.ToList();
        }

        public Product GetProductById(int productId)
        {
            var esResponse = _elasticClient.Search<Product>(x => x.
                             Query(q1 => q1.Bool(b => b.Must(m =>
                             m.Terms(t => t.Field(f => f.ProductId)
                             .Terms<int>(productId))))));

            return esResponse.Documents.FirstOrDefault();
        }

        public void UpdateProduct(Product product)
        {
            
            if (product != null)
            {
                var updateResponse = _elasticClient.UpdateByQueryAsync<Product>(q =>
                                     q.Query(q1 => q1.Bool(b => b.Must(m =>
                                     m.Match(x => x.Field(f =>
                                     f.ProductId == product.ProductId)))))
                                     .Script(s => s.Source(
                                    "ctx._source.price = params.price;" +
                                    "ctx._source.productDescription = params.productDescription;" +
                                    "ctx._source.category = params.category;")
                                    .Lang("painless")
                                    .Params(p => p.Add("price", product.Price)
                                    .Add("productDescription", product.ProductDescription)
                                    .Add("category", product.Category)
                                    )).Conflicts(Conflicts.Proceed));
            }
        }
    }

Now I will create a product controller and consume product services in the controller. We have created four methods: GetProducts, GetProductsById, AddProduct, UpdateProduct, and DeleteProductById.

 public class ProductController : ControllerBase
    {
        private readonly IProductService _productService;
        private readonly ILogger<ProductController> _logger;
        public ProductController(IProductService productService,
            ILogger<ProductController> logger)
        {
            _productService = productService;
            _logger = logger;
        }
       
        [HttpGet]
        [Route("/[controller]/[action]")]
        public IEnumerable<Product> GetProducts()
        {
            return _productService.GetAllProducts();
        }

        [HttpGet]
        [Route("/[controller]/[action]/{id}")]
        public Product GetProductById(int id)
        {
            return _productService.GetProductById(id);
        }

        [HttpPost]
        [Route("api/AddProduct")]
        public void AddProduct([FromBody] Product product)
        {
            _productService.AddProduct(product);
        }

        [HttpPost]
        [Route("api/UpdateProduct")]
        public void UpdateProduct([FromBody] Product product)
        {
            _productService.UpdateProduct(product);
        }

        [HttpDelete]
        [Route("api/DeleteByProductId/{id}")]
        public void Delete(int id)
        {
            _productService.DeleteProduct(id);
        }

        
    }

Now we will build our solution. Once we do build hit F5, we will get a swagger screen as below,

CRUD Operation using Elastic Search

Let's create a new record using the AddProduct method,

CRUD Operation using Elastic Search

Click on the AddProduct method; you will get the above screen. Then click on the Try It Out button. Add the request body as below.

{
  "productId": 1,
  "productName": "Shirt",
  "productDescription": "Full sleeve shirt is for men. This shirt is made from premium quality fabric",
  "price": 700,
  "launchDate": "2023-05-28T10:22:51.537Z",
  "category": "Men's"
}

Once the request body has been added, click the Execute button. A new record will be created in elastic search with API success code 200.

CRUD Operation using Elastic Search

Now let's check if the record was created or not using the GetProducts method. On the below screen, I have highlighted it with a green color.

CRUD Operation using Elastic Search

Let's update records that need updating using UpdateByQueryAsync. Here I will update the same record I just created. Click on the UpdateProduct endpoint below.

CRUD Operation using Elastic Search

Let's change the product description, price, and category fields using the ProductUpdate method, as highlighted in the below screen.

CRUD Operation using Elastic Search

Let's check the updated record using GetProductById.

CRUD Operation using Elastic Search

Let's delete the product using the DeleteProductById method. I will delete the above product with Id = 1.

CRUD Operation using Elastic Search

Let's check if data is deleted for product ID 1 or not using GetProductById.

CRUD Operation using Elastic Search

As per the above screen, GetProductById returns success with 204, meaning no record was found for product ID 1.

Summary

In this article, we have learned about how to perform CRUD operations with elastic search and the .Net Core API. I have demonstrated how to add an elastic client to a.net core project via the start-up class. I have also used UpdateByQueryAsync to update and DeleteByQuery to delete elastic documents.

To read more articles, More Article click here.