Trong phần này chúng ta sẽ tạo một ứng dụng ASP.NET Core với các tính năng tạo (create), đọc (read), cập nhật (update) và xóa (delete) – Ứng dụng CRUD – trên cơ sở dữ liệu NoSQL MongoDB.
Một nhập môn về MongoDB
MongoDB, cơ sở dữ liệu NoSQL phổ biến nhất, là cơ sở dữ liệu hướng tài liệu (document-oriented database) mã nguồn mở. Thuật ngữ “NoSQL” có nghĩa là “không quan hệ” (non-relational). Điều đó có nghĩa là MongoDB không dựa trên cấu trúc cơ sở dữ liệu quan hệ giống như bảng mà cung cấp một cơ chế hoàn toàn khác để lưu trữ và truy xuất dữ liệu. Định dạng lưu trữ này được gọi là BSON (tương tự như định dạng JSON). Một ví dụ:
Cơ sở dữ liệu SQL lưu trữ dữ liệu ở định dạng bảng. Dữ liệu này được lưu trữ trong một mô hình dữ liệu được xác định trước, mô hình này không linh hoạt lắm đối với các ứng dụng đang phát triển cao trong thế giới thực ngày nay. Các ứng dụng hiện đại được kết nối mạng, xã hội và tương tác nhiều hơn bao giờ hết. Các ứng dụng đang lưu trữ ngày càng nhiều dữ liệu và đang truy cập nó với tốc độ cao hơn.
Hệ quản trị cơ sở dữ liệu quan hệ (RDBMS) không phải là lựa chọn phù hợp khi xử lý dữ liệu lớn (big data) vì chúng không có khả năng mở rộng theo chiều ngang. Nếu cơ sở dữ liệu chạy trên một máy chủ duy nhất, thì nó sẽ đạt đến giới hạn mở rộng. Cơ sở dữ liệu NoSQL có khả năng mở rộng cao hơn và cung cấp hiệu suất vượt trội. MongoDB là một cơ sở dữ liệu NoSQL mở rộng quy mô bằng cách thêm ngày càng nhiều máy chủ và tăng năng suất với mô hình tài liệu linh hoạt của nó.
So sánh RDBMS và MongoDB:
- RDBMS có thiết kế lược đồ điển hình hiển thị số lượng bảng (table) và mối quan hệ (relationship) giữa các bảng này trong khi MongoDB là hướng tài liệu (document-oriented). Không có khái niệm về lược đồ hoặc mối quan hệ.
- Các giao dịch phức tạp không được hỗ trợ trong MongoDB vì các hoạt động kết hợp phức tạp không khả dụng.
- MongoDB cho phép cấu trúc tài liệu có khả năng mở rộng và linh hoạt cao. Ví dụ: một tài liệu dữ liệu của một tập hợp trong MongoDB có thể có hai trường trong khi tài liệu khác trong cùng một tập hợp có thể có bốn trường.
- MongoDB nhanh hơn so với RDBMS do kỹ thuật lưu trữ và lập chỉ mục hiệu quả.
- Có một số thuật ngữ có liên quan trong cả hai cơ sở dữ liệu. Cái được gọi là Bảng (Table) trong RDBMS được gọi là Bộ sưu tập (Collection) trong MongoDB. Tương tự, một Tuple (hay Record) được gọi là Tài liệu (Document) và một Cột (Column) được gọi là một Trường (Field). MongoDB cung cấp ‘_id’ mặc định (nếu không được cung cấp rõ ràng) là số thập lục phân 12 byte đảm bảo tính duy nhất của mọi tài liệu. Nó tương tự như khóa chính (primary key) trong RDBMS.
Các đặc trưng của MongoDB
- Hướng tài liệu (Document Oriented): MongoDB lưu trữ chủ đề chính với số lượng tài liệu tối thiểu và không phải bằng cách chia nó thành nhiều cấu trúc quan hệ như RDBMS. Ví dụ, nó lưu trữ tất cả thông tin của một máy tính trong một tài liệu duy nhất được gọi là Máy tính và không nằm trong các cấu trúc quan hệ riêng biệt như CPU, RAM, đĩa cứng, v.v.
- Lập chỉ mục (Indexing): Nếu không lập chỉ mục, cơ sở dữ liệu sẽ phải quét mọi tài liệu của bộ sưu tập để chọn những tài liệu phù hợp với truy vấn sẽ không hiệu quả. Vì vậy, để tìm kiếm hiệu quả Lập chỉ mục là điều bắt buộc và MongoDB sử dụng nó để xử lý khối lượng dữ liệu khổng lồ trong thời gian rất ngắn.
- Khả năng mở rộng (Scalability): MongoDB mở rộng quy mô theo chiều ngang bằng cách sử dụng phân đoạn (sharding) (phân vùng dữ liệu trên các máy chủ khác nhau). Dữ liệu được phân vùng thành các phần dữ liệu bằng cách sử dụng khóa phân đoạn và các phần dữ liệu này được phân bổ đồng đều trên các phân đoạn nằm trên nhiều máy chủ vật lý. Ngoài ra, các máy mới có thể được thêm vào cơ sở dữ liệu đang chạy.
- Nhân rộng và Tính khả dụng cao (Replication and High Availability): MongoDB tăng tính khả dụng của dữ liệu với nhiều bản sao dữ liệu trên các máy chủ khác nhau. Bằng cách cung cấp dự phòng, nó bảo vệ cơ sở dữ liệu khỏi các lỗi phần cứng. Nếu một máy chủ gặp sự cố, dữ liệu có thể được truy xuất dễ dàng từ các máy chủ đang hoạt động khác cũng có dữ liệu được lưu trữ trên chúng.
- Tổng hợp (Aggregation): Các hoạt động tổng hợp xử lý các bản ghi dữ liệu và trả về các kết quả đã tính toán. Nó tương tự như mệnh đề GROUP BY trong SQL. Một số biểu thức tổng hợp là sum, average, min, max, v.v.
Khi nào dùng MongoDB
MongoDB được ưu tiên sử dụng trong các trường hợp:
- Dữ liệu lớn (Big Data): Nếu bạn có một lượng lớn dữ liệu được lưu trữ trong các bảng, hãy nghĩ đến MongoDB trước cơ sở dữ liệu RDBMS. MongoDB có giải pháp tích hợp để phân vùng và làm sắc nét cơ sở dữ liệu của bạn.
- Lược đồ không ổn định (Unstable Schema): Việc thêm một cột mới trong RDBMS rất khó trong khi MongoDB là một lược đồ ít hơn. Việc thêm một trường mới không ảnh hưởng đến các tài liệu cũ và sẽ rất dễ dàng.
- Dữ liệu phân tán (Distributed data): Vì nhiều bản sao dữ liệu được lưu trữ trên các máy chủ khác nhau nên việc khôi phục dữ liệu diễn ra tức thì và an toàn ngay cả khi có lỗi phần cứng.
Cấu hình MongoDB
– Tải MongoDB tại https://www.mongodb.com/try/download/community?tck=docs_server&_ga=2.48130151.1128304397.1645427554-1872487359.1645427554 và thực hiện các bước cài đặt tại https://docs.mongodb.com/manual/tutorial/install-mongodb-on-windows-unattended/

Nhấn Next, chọn I accept the items…

Nhấn Next, chọn Complete

Chấp nhận các tùy chọn mặc định (ghi nhớ đường dẫn dữ liệu tại Data Directory), nhấn Next, Next và Install

Cài thành công

Nhấn Finish

Nhấn Yes để khởi động lại máy tính.
Tải MongoDB Shell bằng cách truy cập https://www.mongodb.com/try/download/shell?jmp=docs&_ga=2.210126805.1128304397.1645427554-1872487359.1645427554 và tải MongoDB Shell (mogosh).
Chạy tập tin msi vừa tải

Nhấn Next

Nhấn Next và Install

Nhấn Finish.
Thêm C:\Program Files\MongoDB\Server\<version_number>\bin (trong minh họa của chúng ta là C:\Program Files\MongoDB\Server\5.0\bin) đến biến môi trường Path bằng cách (trong Windows 10):
– Nhấn chuột phải vào biểu tượng This PC trên Desktop, chọn Properties
– Chọn Advanced system settings trong cửa sổ Settings
– Chọn Environment Variables… trong hộp thoại System Properties và chọn Path tại khung System variables trong hộp Environment Variables

– Chọn Edit > Browse và chọn C:\Program Files\MongoDB\Server\5.0\bin. Nhấn OK và đóng tất cả các hộp thoại.
Cấu hình MongoDB
– Tạo một thư mục chứa dữ liệu, ví dụ D:\BooksData
– Mở cmd và gõ mongod –dbpath D:\BooksData
– Mở một cửa sổ cmd khác và gõ lệnh mongosh

– Tại con trỏ test> gõ use BookstoreDB và Enter. Cơ sở dữ liệu tên BookstoreDB được tạo ra

– Tạo một collection tên Books bằng cách gõ db.createCollection(‘Books’) sẽ xuất hiện { “ok” : 1 } như hình

– Định nghĩa một lược đồ cho Books và chèn hai tài liệu (dữ liệu trong NoSQL gọi là các document thay vì gọi là các record ) bằng lệnh sau:
db.Books.insertMany([{'Name':'Design Patterns','Price':54.93,'Category':'Computers','Author':'Ralph Johnson'}, {'Name':'Clean Code','Price':43.15,'Category':'Computers','Author':'Robert C. Martin'}])
Kết quả
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("5bfd996f7b8e48dc15ff215d"),
ObjectId("5bfd996f7b8e48dc15ff215e")
]
}
Như hình

– Dùng lệnh db.Books.find({}).pretty() để xem dữ liệu vừa thêm đến cơ sở dữ liệu

Lược đồ tự thêm các _id đến các tài liệu. Cơ sở dữ liệu đã sẵn sàng được dùng.
Tạo dự án ASP.NET Core web API
Tạo dự án ASP.NET Core web API mới tương tự phần 1. Tạo một dự án Web API với Controller, chỉ khác là đặt tên dự án là BooksApi.
Truy cập trang https://www.nuget.org/packages/MongoDB.Driver/ để xem phiên bản mới nhất của .NET driver dùng cho MongoDB. Phiên bản mới nhất thời điểm viết bài này là 2.14.1

– Sau khi xác định số hiệu phiên bản mới nhất, cài đặt .NET driver cho MongoDB bằng cách vào Tools > Nuget Package Manager > Package Manager Console và thực thi lệnh Install-Package MongoDB.Driver -Version {VERSION} với VERSION là số hiệu phiên bản mới nhất, trong bài này là 2.14.1. Như vậy, lệnh của chúng ta là Install-Package MongoDB.Driver -Version {2.14.1}

Thêm lớp dữ liệu (model class)
Thêm một thư mục tên Models đến dự án. Trong thư mục này thêm lớp Book và thay đổi nội dung mặc định lớp này bằng nội dung sau:
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
namespace BooksApi.Models
{
public class Book
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
[BsonElement("Name")]
public string BookName { get; set; }
public decimal Price { get; set; }
public string Category { get; set; }
public string Author { get; set; }
}
}
Thuộc tính Id được yêu cầu:
– Để ánh xạ đối tượng CLR đến collection của MongoDB
– Thuộc tính [BsonId] xác nhận Id là khóa chính
– Thuộc tính [BsonRepresentation(BsonType.ObjectId)] cho phép truyền tham số như kiểu string thay vì kiểu cấu trúc ObjectId. Mongo sẽ chuyển kiểu từ string đến ObjectId.
– [BsonElement(“Name”)] xác nhận thuộc tính BookName là thuộc tính Name từ collection của MongoDB
Cấu hình dữ liệu
– Mở tập tin appsettings.json và thêm nội dung sau:
{
"BookstoreDatabaseSettings": {
"BooksCollectionName": "Books",
"ConnectionString": "mongodb://localhost:27017",
"DatabaseName": "BookstoreDB"
},
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Warning"
}
},
"Console": {
"LogLevel": {
"Default": "Warning"
}
}
}
}
Thuộc tính BookstoreDatabaseSettings sẽ có các thuộc tính:
- BooksCollectionName: là collection chúng ta đã thêm vào cơ sở dữ liệu MongoDB ở trên, cụ thể là Books.
- ConnectionString: đường dẫn đến máy chủ cục bộ MongoDB. Cổng mặc định cho máy chủ cục bộ MongoDB là 27017.
- DatabaseName: là cơ sở dữ liệu chúng ta đã tạo từ MongoDB ở trên, cụ thể là BookstoreDB.
– Thêm một lớp tên BookstoreDatabaseSettings đến thư mục Models và thay đổi nội dung mặc định như sau:
namespace BooksApi.Models
{
public class BookstoreDatabaseSettings : IBookstoreDatabaseSettings
{
public string BooksCollectionName { get; set; }
public string ConnectionString { get; set; }
public string DatabaseName { get; set; }
}
public interface IBookstoreDatabaseSettings
{
string BooksCollectionName { get; set; }
string ConnectionString { get; set; }
string DatabaseName { get; set; }
}
}
Lớp BookstoreDatabaseSettings được dùng để lưu trữ giá trị thuộc tính BookstoreDatabaseSettings trong tập tin appsettings.json ở trên. Thuộc tính JSON và thuộc tính C# đặt trùng tên để dẽ dàng ánh xạ qua lại.
– Mở tập tin Startup.cs và thêm nội dung sau đến phương thức ConfigureServices:
using BooksApi.Models;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
public void ConfigureServices(IServiceCollection services)
{
// requires using Microsoft.Extensions.Options
services.Configure<BookstoreDatabaseSettings>(
Configuration.GetSection(nameof(BookstoreDatabaseSettings)));
services.AddSingleton<IBookstoreDatabaseSettings>(sp =>
sp.GetRequiredService<IOptions<BookstoreDatabaseSettings>>().Value);
services.AddControllers();
}
Đoạn mã trên có hai mục đích:
- Cấu hình các thành phần ràng buộc đến thuộc tính BookstoreDatabaseSettings trong tập tin appsettings.json được đăng ký đến bộ chứa DI (Dependency Injection) của ASP.NET Core. Ví dụ thuộc tinh ConnectionString của đối tượng BookstoreDatabaseSettings sẽ kết xuất đến BookstoreDatabaseSettings:ConnectionString trong tập tin appsettings.json.
- Giao diện IBookstoreDatabaseSettings được đăng ký đến bộ chứa DI với thời gian sống kiểu Singleton( https://docs.microsoft.com/en-us/dotnet/core/extensions/dependency-injection#service-lifetimes ). Các dịch vụ đăng ký kiểu Singleton được tạo ra bằng một trong hai cách: Tạo ra lần đầu tiên khi chúng yêu cầu hay tạo bởi nhà phát triển cung cấp một thể hiện thực thi trực tiếp đến bộ chứa. Khi được đăng ký, thể hiện giao diện phân giải đến một đối tượng BookstoreDatabaseSettings.
Thêm một dịch vụ các thao tác CRUD (Create, Read, Update, Delete)
Thêm một thư mục tên Services đến dự án. Thêm lớp BookService đến thư mục này với nội dung như sau:
using BooksApi.Models;
using MongoDB.Driver;
using System.Collections.Generic;
using System.Linq;
namespace BooksApi.Services
{
public class BookService
{
private readonly IMongoCollection<Book> _books;
public BookService(IBookstoreDatabaseSettings settings)
{
var client = new MongoClient(settings.ConnectionString);
var database = client.GetDatabase(settings.DatabaseName);
_books = database.GetCollection<Book>(settings.BooksCollectionName);
}
public List<Book> Get() =>
_books.Find(book => true).ToList();
public Book Get(string id) =>
_books.Find<Book>(book => book.Id == id).FirstOrDefault();
public Book Create(Book book)
{
_books.InsertOne(book);
return book;
}
public void Update(string id, Book bookIn) =>
_books.ReplaceOne(book => book.Id == id, bookIn);
public void Remove(Book bookIn) =>
_books.DeleteOne(book => book.Id == bookIn.Id);
public void Remove(string id) =>
_books.DeleteOne(book => book.Id == id);
}
}
Trong đoạn mã trên, một thể hiện giao diện IBookstoreDatabaseSettings được nhận từ DI qua phương thức khởi tạo. Điều này giúp chúng ta truy cập đến các giá trị cấu hình từ tập tin appsettings.json được thêm từ phần trên.
– Thêm đoạn mã sau đến phương thức ConfigureServices của tập tin Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<BookstoreDatabaseSettings>(
Configuration.GetSection(nameof(BookstoreDatabaseSettings)));
services.AddSingleton<IBookstoreDatabaseSettings>(sp =>
sp.GetRequiredService<IOptions<BookstoreDatabaseSettings>>().Value);
services.AddSingleton<BookService>();
services.AddControllers();
}
Chú ý thêm using BooksApi.Services.
Lớp BookService dùng các thành viên từ MongoDB.Driver để thực hiện các thao tác CRUD:
- MongoClient (https://mongodb.github.io/mongo-csharp-driver/2.11/apidocs/html/T_MongoDB_Driver_MongoClient.htm ): Đọc thể hiện máy chủ để chạy các thao tác cơ sở dữ liệu. Phương thức khởi tạo của lớp này được cung cấp chuỗi kết nối đến máy chủ MongoDB.
public BookService(IBookstoreDatabaseSettings settings)
{
var client = new MongoClient(settings.ConnectionString);
var database = client.GetDatabase(settings.DatabaseName);
_books = database.GetCollection<Book>(settings.BooksCollectionName);
}
- IMongoDatabase (https://mongodb.github.io/mongo-csharp-driver/2.11/apidocs/html/T_MongoDB_Driver_IMongoDatabase.htm ): Thể hiện cơ sở dữ liệu Mongo cho các thao tác chạy. Bài viết này dùng phương thức generic GetCollection<TDocument>(collection) (https://mongodb.github.io/mongo-csharp-driver/2.11/apidocs/html/M_MongoDB_Driver_IMongoDatabase_GetCollection__1.htm ) để truy cập đến dữ liệu trong một collection cụ thể với collection là tên collection (ví dụ Books), TDocument là kiểu đối tượng CLR trong collection. Các thao tác CRUD thực thi sau khi phương thức này được gọi.
Phương thức GetCollection trả về một đối tượng MongoCollection (https://mongodb.github.io/mongo-csharp-driver/2.11/apidocs/html/T_MongoDB_Driver_MongoCollection.htm ) thể hiện collection. Các phương thức chính được sử dụng trong bài này từ đối tượng trên gồm:
- DeleteOne (https://mongodb.github.io/mongo-csharp-driver/2.11/apidocs/html/M_MongoDB_Driver_IMongoCollection_1_DeleteOne.htm ): Xóa một document theo điều kiện.
- Find<TDocument> (https://mongodb.github.io/mongo-csharp-driver/2.11/apidocs/html/M_MongoDB_Driver_IMongoCollectionExtensions_Find__1_1.htm ): Trả về các document theo điều kiện.
- InsertOne (https://mongodb.github.io/mongo-csharp-driver/2.11/apidocs/html/M_MongoDB_Driver_IMongoCollection_1_InsertOne.htm ): Chèn một đối tượng như một document mới đến collection.
- ReplaceOne (https://mongodb.github.io/mongo-csharp-driver/2.11/apidocs/html/M_MongoDB_Driver_IMongoCollection_1_ReplaceOne.htm ): Thay thế một document bằng một document khác.
Thêm một Controller
Thêm lớp BooksController đến thư mục Controllers với nội dung sau:
using BooksApi.Models;
using BooksApi.Services;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
namespace BooksApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class BooksController : ControllerBase
{
private readonly BookService _bookService;
public BooksController(BookService bookService)
{
_bookService = bookService;
}
[HttpGet]
public ActionResult<List<Book>> Get() =>
_bookService.Get();
[HttpGet("{id:length(24)}", Name = "GetBook")]
public ActionResult<Book> Get(string id)
{
var book = _bookService.Get(id);
if (book == null)
{
return NotFound();
}
return book;
}
[HttpPost]
public ActionResult<Book> Create(Book book)
{
_bookService.Create(book);
return CreatedAtRoute("GetBook", new { id = book.Id.ToString() }, book);
}
[HttpPut("{id:length(24)}")]
public IActionResult Update(string id, Book bookIn)
{
var book = _bookService.Get(id);
if (book == null)
{
return NotFound();
}
_bookService.Update(id, bookIn);
return NoContent();
}
[HttpDelete("{id:length(24)}")]
public IActionResult Delete(string id)
{
var book = _bookService.Get(id);
if (book == null)
{
return NotFound();
}
_bookService.Remove(id);
return NoContent();
}
}
}
Đoạn mã trên có một số lưu ý sau:
- Dùng lớp BookService để thực hiện các thao tác CRUD.
- Chứa các phương thức hành động hỗ trợ các yêu cầu HTTP là GET, PUT, POST và DELETE.
- Gọi CreateAtRoute trong phương thức Create để trả về mã trạng thái 201. (Xem lại bài 1. Tạo một dự án Web API với Controller)
Kiểm tra ứng dụng
Thực thi ứng dụng với URL https://localhost:<port>/api/books (bài viết này dùng port 44322)

Dữ liệu
[{"id":"62145f227c4ebe967a194caf","bookName":"Design Patterns","price":54.93,"category":"Computers","author":"Ralph Johnshon"},{"id":"62145f227c4ebe967a194cb0","bookName":"Clean Code","price":43.15,"category":"Computers","author":"Robert C. Martin"}]
Các thuộc tính bookName, author, price, category và author không khớp với các thuộc tính đã được định nghĩa trong lớp Book (trong tập tin Models/Book.cs). Điều chúng ta mong đợi là:
- Name thay vì bookName
- Author thay vì author
- Category thay vì category
- Price thay vì price
Để thực điều này, chúng ta sẽ thực hiện cấu hình lại các tùy chọn kết xuất JSON.
Cấu hình các tùy chọn kết xuất JSON
Thêm gói Microsoft.AspNetCore.Mvc.NewtonsoftJson (https://www.nuget.org/packages/Microsoft.AspNetCore.Mvc.NewtonsoftJson ) đến dự án bằng cách vào Tools > Nuget Package Manager > Package Manager Console. Gõ lênh:
Install-Package Microsoft.AspNetCore.Mvc.NewtonsoftJson -Version 3.0.0
Thời điểm đang viết bài này đang là phiên bản 6.X nhưng vì chúng ta đang dùng ASP.NET Core 3.1 nên cài phiên bản 3.X là phù hợp. Ở đây dùng 3.0.0.
Trong phương thức ConfigureServices của tập tin Startup.cs, thay đổi
services.AddControllers();
thành
services.AddControllers()
.AddNewtonsoftJson(options => options.UseMemberCasing());
Bằng cách thêm gói Microsoft.AspNetCore.Mvc.NewtonsoftJson và điều chỉnh phương thức AddControllers, các thuộc tính dữ liệu JSON truy xuất từ Web API sẽ khớp với các thuộc tính kiểu CLR hay lớp Book.
Thực thi ứng dụng, dữ liệu lúc này:
[{"Id":"62145f227c4ebe967a194caf","BookName":"Design Patterns","Price":54.93,"Category":"Computers","Author":"Ralph Johnshon"},{"Id":"62145f227c4ebe967a194cb0","BookName":"Clean Code","Price":43.15,"Category":"Computers","Author":"Robert C. Martin"}]
Để ý, kiểu camel được thay bằng kiểu Pascal như trong lớp Book (tức kiểu CLR)
- BookName thay vì bookName
- Author thay vì author
- Category thay vì category
- Price thay vì price
Nếu chúng ta muốn thay BookName bằng Name, trong lớp Book từ tập tin Models/Book.cs, thêm thuộc tính [JsonProperty] đến trường BookName:
[BsonElement("Name")]
[JsonProperty("Name")]
public string BookName { get; set; }
Lưu ý thêm using Newtonsoft.Json;
Với việc thêm thuộc tính [JsonProperty(“Name”)], thuộc tính bookName từ dữ liệu kết xuất JSON sẽ được thay bằng Name.
Thực thi lại ứng dụng, dữ liệu nhận được sẽ là:
[{"Id":"62145f227c4ebe967a194caf","Name":"Design Patterns","Price":54.93,"Category":"Computers","Author":"Ralph Johnshon"},{"Id":"62145f227c4ebe967a194cb0","Name":"Clean Code","Price":43.15,"Category":"Computers","Author":"Robert C. Martin"}]