diff --git a/docs/howtos/solutions/caching-architecture/write-behind/index-write-behind.mdx b/docs/howtos/solutions/caching-architecture/write-behind/index-write-behind.mdx index ce29b3ea2a..cd3fb298f0 100644 --- a/docs/howtos/solutions/caching-architecture/write-behind/index-write-behind.mdx +++ b/docs/howtos/solutions/caching-architecture/write-behind/index-write-behind.mdx @@ -16,6 +16,8 @@ import mongoCompassImage from './images/mongo-compass.png'; + + ## What is write-behind caching? Imagine you've built a movie streaming app. You used MongoDB as your data store, and as you needed to scale you implemented caching using Redis. This allows you to drastically speed up reads. However, now you are experiencing slowness when writing to MongoDB. diff --git a/docs/howtos/solutions/microservices/api-gateway-caching/index-api-gateway-caching.mdx b/docs/howtos/solutions/microservices/api-gateway-caching/index-api-gateway-caching.mdx index d00a026377..927377d619 100644 --- a/docs/howtos/solutions/microservices/api-gateway-caching/index-api-gateway-caching.mdx +++ b/docs/howtos/solutions/microservices/api-gateway-caching/index-api-gateway-caching.mdx @@ -32,7 +32,7 @@ While this works, you end up with a fair amount of duplicated code. Plus, it's d Once you decide to handle authentication at the API gateway layer, you must decide where to store sessions. -Imagine you're building an e-commerce application that uses MongoDB as the primary data store. You could store sessions in MongoDB, but think about how many times the application needs to hit MongoDB to retrieve session information. If you have millions of customers, you don't want to go to MongoDB for every single request made to the API. +Imagine you're building an e-commerce application that uses MongoDB/ any relational database as the primary data store. You could store sessions in primary database, but think about how many times the application needs to hit primary database to retrieve session information. If you have millions of customers, you don't want to go to database for every single request made to the API. This is where Redis comes in. @@ -60,7 +60,7 @@ Use a **Redis Enterprise Cluster** to get the benefit of linear scaling to ensur -## API gateway caching in a microservices application with Redis and MongoDB +## API gateway caching in a microservices application with Redis What's nice about a microservice architecture is that each service is set up so it can scale independently. Now, seeing as how each service might require authentication, you likely want to obtain session information for most requests. Therefore, it makes sense to use the API gateway to cache and retrieve session information and to subsequently pass the information on to each service. Let's see how you might accomplish this. diff --git a/docs/howtos/solutions/microservices/caching/index-caching.mdx b/docs/howtos/solutions/microservices/caching/index-caching.mdx index 9f17350675..81d17d21e6 100644 --- a/docs/howtos/solutions/microservices/caching/index-caching.mdx +++ b/docs/howtos/solutions/microservices/caching/index-caching.mdx @@ -24,7 +24,7 @@ import cacheHitImage from './images/redis-cache-aside-cache-hit.png'; Have you ever been in a situation where your database queries are slowing down? Query caching is the technique you need to speed database queries by using different caching methods while keeping costs down! Imagine that you built an e-commerce application. It started small but is growing fast. By now, you have an extensive product catalog and millions of customers. -That’s good for business, but a hardship for technology. Your queries to MongoDB are beginning to slow down, even though you already attempted to optimize them. Even though you can squeak out a little extra performance, it isn’t enough to satisfy your customers. +That's good for business, but a hardship for technology. Your queries to primary database (MongoDB/ Postgressql) are beginning to slow down, even though you already attempted to optimize them. Even though you can squeak out a little extra performance, it isn't enough to satisfy your customers. ## Why you should use Redis for query caching @@ -99,7 +99,7 @@ If you use **Redis Enterprise** and a database that uses a JDBC driver, you can -## Caching in a microservices application with Redis and MongoDB +## Caching in a microservices application with Redis and primary database (MongoDB/ Postgressql) In our sample application, the products service publishes an API for filtering products. Here's what a call to the API looks like: @@ -114,32 +114,27 @@ In our sample application, the products service publishes an API for filtering p ### Get products by filter response (cache miss) -```json {30} +```json {25} { "data": [ { - "_id": 11000, - "data": { - "id": 11000, - "price": 3995, - "productDisplayName": "Puma Men Slick 3HD Yellow Black Watches", - "variantName": "Slick 3HD Yellow", - "brandName": "Puma", - "ageGroup": "Adults-Men", - "gender": "Men", - "displayCategories": "Accessories", - "styleImages": { - "default": { - "imageURL": "http://host.docker.internal:8080/images/11000.jpg" - } - }, - "productDescriptors": { - "description": { - "value": "Stylish and comfortable, this motor sport inspired wrist watch from puma is designed with a plastic case and ..." - } - } - }, - "productId": 11000 + "productId": "11000", + "price": 3995, + "productDisplayName": "Puma Men Slick 3HD Yellow Black Watches", + "variantName": "Slick 3HD Yellow", + "brandName": "Puma", + "ageGroup": "Adults-Men", + "gender": "Men", + "displayCategories": "Accessories", + "masterCategory_typeName": "Accessories", + "subCategory_typeName": "Watches", + "styleImages_default_imageURL": "http://host.docker.internal:8080/images/11000.jpg", + "productDescriptors_description_value": "

Stylish and comfortable, ...", + "createdOn": "2023-07-13T14:07:38.020Z", + "createdBy": "ADMIN", + "lastUpdatedOn": "2023-07-13T14:07:38.020Z", + "lastUpdatedBy": null, + "statusCode": 1 } //... ], @@ -160,66 +155,36 @@ In our sample application, the products service publishes an API for filtering p } ``` -### Implementing cache-aside with Redis and MongoDB +### Implementing cache-aside with Redis and primary database (MongoDB/ Postgressql) -The following code shows the function used to search for products in MongoDB: +The following code shows the function used to search for products in primary database: ```typescript title="server/src/services/products/src/service-impl.ts" -async function getProductsByFilter(productFilter: IProductFilter) { - const mongo = getMongodb(); - const filter: Document = { - statusCode: { - $eq: DB_ROW_STATUS.ACTIVE, - }, +async function getProductsByFilter(productFilter: Product) { + const prisma = getPrismaClient(); + + const whereQuery: Prisma.ProductWhereInput = { + statusCode: DB_ROW_STATUS.ACTIVE, }; if (productFilter && productFilter.productDisplayName) { - filter['data.productDisplayName'] = { - $regex: productFilter.productDisplayName, - $options: 'i', + whereQuery.productDisplayName = { + contains: productFilter.productDisplayName, + mode: 'insensitive', }; } - const projection: IProduct = { - productId: 1, - data: { - id: 1, - price: 1, - productDisplayName: 1, - variantName: 1, - brandName: 1, - ageGroup: 1, - gender: 1, - displayCategories: 1, - styleImages: { - default: { - imageURL: 1, - }, - }, - productDescriptors: { - description: { - value: 1, - }, - }, - }, - }; + const products: Product[] = await prisma.product.findMany({ + where: whereQuery, + }); - const limit = 100; - const sort = {}; - const products = await mongo.find( - COLLECTIONS.PRODUCTS.collectionName, - filter, - projection, - limit, - sort, - ); return products; } ``` -If you're familiar with MongoDB, this code should be pretty straightforward. You simply make a call to MongoDB to find products based on a filter on the product’s `displayName` property. You also define a projection object to specify which properties to get out of MongoDB. You can set up multiple columns for better fuzzy searching, but we simplified it for the purposes of this tutorial. +You simply make a call to primary database (MongoDB/ Postgressql) to find products based on a filter on the product's `displayName` property. You can set up multiple columns for better fuzzy searching, but we simplified it for the purposes of this tutorial. -Using MongoDB directly without Redis works for a while, but eventually it slows down. That's why you might use Redis, to speed things up. The cache-aside pattern helps you balance performance with cost. +Using primary database directly without Redis works for a while, but eventually it slows down. That's why you might use Redis, to speed things up. The cache-aside pattern helps you balance performance with cost. The basic decision tree for cache-aside is as follows. @@ -228,7 +193,7 @@ When the frontend requests products: 1. Form a hash with the contents of the request (i.e., the search parameters). 1. Check Redis to see if a value exists for the hash. 1. Is there a cache hit? If data is found for the hash, it is returned; the process stops here. -1. Is there a cache miss? When data is not found, it is read out of MongoDB and subsequently stored in Redis prior to being returned. +1. Is there a cache miss? When data is not found, it is read out of primary database and subsequently stored in Redis prior to being returned. Here’s the code used to implement the decision tree: @@ -256,7 +221,7 @@ router.post(API.GET_PRODUCTS_BY_FILTER, async (req: Request, res: Response) => { result.data = docArr; result.isFromCache = true; } else { - // get data from mongodb + // get data from primary database const dbData = await getProductsByFilter(body); //method shown earlier if (body && body.productDisplayName && dbData.length) { diff --git a/docs/howtos/solutions/microservices/common-data/microservices-arch-with-redis-old.mdx b/docs/howtos/solutions/microservices/common-data/microservices-arch-with-redis-old.mdx new file mode 100644 index 0000000000..fe4df59d0e --- /dev/null +++ b/docs/howtos/solutions/microservices/common-data/microservices-arch-with-redis-old.mdx @@ -0,0 +1,10 @@ +The e-commerce microservices application discussed in the rest of this tutorial uses the following architecture: + +1. `products service`: handles querying products from the database and returning them to the frontend +1. `orders service`: handles validating and creating orders +1. `order history service`: handles querying a customer's order history +1. `payments service`: handles processing orders for payment +1. `digital identity service`: handles storing digital identity and calculating identity score +1. `api gateway`: unifies services under a single endpoint +1. `mongodb`: serves as the primary database, storing orders, order history, products, etc. +1. `redis`: serves as the **stream processor** and caching database diff --git a/docs/howtos/solutions/microservices/common-data/microservices-arch-with-redis.mdx b/docs/howtos/solutions/microservices/common-data/microservices-arch-with-redis.mdx index 7f65be673d..282a895298 100644 --- a/docs/howtos/solutions/microservices/common-data/microservices-arch-with-redis.mdx +++ b/docs/howtos/solutions/microservices/common-data/microservices-arch-with-redis.mdx @@ -6,5 +6,11 @@ The e-commerce microservices application discussed in the rest of this tutorial 1. `payments service`: handles processing orders for payment 1. `digital identity service`: handles storing digital identity and calculating identity score 1. `api gateway`: unifies services under a single endpoint -1. `mongodb`: serves as the primary database, storing orders, order history, products, etc. -1. `redis`: serves as the stream processor and caching database +1. `mongodb/ postgresql`: serves as the primary database, storing orders, order history, products, etc. +1. `redis`: serves as the **stream processor** and caching database + +:::info + +You don't need to use MongoDB/ Postgresql as your primary database in the demo application; you can use other [prisma supported databases](https://www.prisma.io/docs/reference/database-reference/supported-databases) as well. This is just an example. + +::: diff --git a/docs/howtos/solutions/microservices/common-data/microservices-arch.mdx b/docs/howtos/solutions/microservices/common-data/microservices-arch.mdx index caf295b901..95d2b74d4a 100644 --- a/docs/howtos/solutions/microservices/common-data/microservices-arch.mdx +++ b/docs/howtos/solutions/microservices/common-data/microservices-arch.mdx @@ -5,10 +5,10 @@ You eventually land on the following architecture: 1. `order history service`: handles querying a customer's order history 1. `payments service`: handles processing orders for payment 1. `api gateway`: unifies the services under a single endpoint -1. `mongodb`: serves as the write-optimized database for storing orders, order history, products, etc. +1. `mongodb/ postgresql`: serves as the write-optimized database for storing orders, order history, products, etc. :::info -You don’t need to use MongoDB as your write-optimized database; you can use other databases such as a SQL database as well. This is just an example. +You don't need to use MongoDB/ Postgresql as your write-optimized database in the demo application; you can use other [prisma supported databases](https://www.prisma.io/docs/reference/database-reference/supported-databases) as well. This is just an example. ::: diff --git a/docs/howtos/solutions/microservices/common-data/microservices-ecommerce-old.mdx b/docs/howtos/solutions/microservices/common-data/microservices-ecommerce-old.mdx new file mode 100644 index 0000000000..88f06afcf3 --- /dev/null +++ b/docs/howtos/solutions/microservices/common-data/microservices-ecommerce-old.mdx @@ -0,0 +1,13 @@ +The e-commerce microservices application consists of a frontend, built using [Next.js](https://nextjs.org/) with [TailwindCSS](https://tailwindcss.com/). The application backend uses [Node.js](https://nodejs.org). The data is stored in +[Redis](https://redis.com/try-free/) and MongoDB. Below you will find screenshots of the frontend of the e-commerce app: + +- `Dashboard`: Shows the list of products with search functionality + + ![redis microservices e-commerce app frontend products page](images/design-dashboard.png) + +- `Shopping Cart`: Add products to the cart, then check out using the "Buy Now" button + ![redis microservices e-commerce app frontend shopping cart](images/design-cart-2.png) + +- `Order history`: Once an order is placed, the `Orders` link in the top navigation bar shows the order status and history + + ![redis microservices e-commerce app frontend order history page](images/design-order-history.png) diff --git a/docs/howtos/solutions/microservices/common-data/microservices-ecommerce.mdx b/docs/howtos/solutions/microservices/common-data/microservices-ecommerce.mdx index c84fbe0162..62ef1b49cd 100644 --- a/docs/howtos/solutions/microservices/common-data/microservices-ecommerce.mdx +++ b/docs/howtos/solutions/microservices/common-data/microservices-ecommerce.mdx @@ -1,4 +1,5 @@ -The e-commerce microservices application consists of a frontend, built using [Next.js](https://nextjs.org/) with [TailwindCSS](https://tailwindcss.com/). The application backend uses [Node.js](https://nodejs.org). The data is stored in [MongoDB](https://www.mongodb.com/) and [Redis](https://redis.com/try-free/). Below you will find screenshots of the frontend of the e-commerce app: +The e-commerce microservices application consists of a frontend, built using [Next.js](https://nextjs.org/) with [TailwindCSS](https://tailwindcss.com/). The application backend uses [Node.js](https://nodejs.org). The data is stored in +[Redis](https://redis.com/try-free/) and MongoDB/ Postgressql using [Prisma](https://www.prisma.io/docs/reference/database-reference/supported-databases). Below you will find screenshots of the frontend of the e-commerce app: - `Dashboard`: Shows the list of products with search functionality diff --git a/docs/howtos/solutions/microservices/common-data/microservices-source-code-tip-old.mdx b/docs/howtos/solutions/microservices/common-data/microservices-source-code-tip-old.mdx new file mode 100644 index 0000000000..1de0c9f615 --- /dev/null +++ b/docs/howtos/solutions/microservices/common-data/microservices-source-code-tip-old.mdx @@ -0,0 +1,7 @@ +:::tip GITHUB CODE + +Below is a command to the clone the source code for the application used in this tutorial + +git clone --branch v1.0.0 https://github.com/redis-developer/redis-microservices-ecommerce-solutions + +::: diff --git a/docs/howtos/solutions/microservices/common-data/microservices-source-code-tip.mdx b/docs/howtos/solutions/microservices/common-data/microservices-source-code-tip.mdx index 1de0c9f615..c3a5c22dc4 100644 --- a/docs/howtos/solutions/microservices/common-data/microservices-source-code-tip.mdx +++ b/docs/howtos/solutions/microservices/common-data/microservices-source-code-tip.mdx @@ -2,6 +2,6 @@ Below is a command to the clone the source code for the application used in this tutorial -git clone --branch v1.0.0 https://github.com/redis-developer/redis-microservices-ecommerce-solutions +git clone --branch v4.2.0 https://github.com/redis-developer/redis-microservices-ecommerce-solutions ::: diff --git a/docs/howtos/solutions/microservices/cqrs/images/redis-1-order-with-products.png b/docs/howtos/solutions/microservices/cqrs/images/redis-1-order-with-products.png new file mode 100644 index 0000000000..dea925a123 Binary files /dev/null and b/docs/howtos/solutions/microservices/cqrs/images/redis-1-order-with-products.png differ diff --git a/docs/howtos/solutions/microservices/cqrs/index-cqrs.mdx b/docs/howtos/solutions/microservices/cqrs/index-cqrs.mdx index 857dd9b745..36e418c537 100644 --- a/docs/howtos/solutions/microservices/cqrs/index-cqrs.mdx +++ b/docs/howtos/solutions/microservices/cqrs/index-cqrs.mdx @@ -14,6 +14,7 @@ import RedisEnterprise from '../common-data/redis-enterprise.mdx'; import cqrsPattern from './images/cqrs-pattern.png'; import cqrsArchitectureWithCdc from './images/cqrs-architecture-with-cdc.png'; +import imageSampleOrder from './images/redis-1-order-with-products.png'; @@ -82,7 +83,7 @@ When your e-commerce application eventually needs to scale across the globe, Red ::: -Let's look at some sample code that helps facilitate the CQRS pattern with Redis and MongoDB. +Let's look at some sample code that helps facilitate the CQRS pattern with Redis and Primary database (MongoDB/ Postgressql). ## E-commerce application frontend using Next.js and Tailwind @@ -90,7 +91,7 @@ Let's look at some sample code that helps facilitate the CQRS pattern with Redis -## Building a CQRS microservices application with Redis and MongoDB +## Building a CQRS microservices application with Redis and Primary database (MongoDB/ Postgressql) Let's look at the sample code for the `order service` and see the `CreateOrder` command (a write operation). Then we look at the `order history service` to see the `ViewOrderHistory` command (a read operation). @@ -105,14 +106,14 @@ The code that follows shows an example API request and response to create an ord { "products": [ { - "productId": 11000, - "qty": 2, - "productPrice": 3995 + "productId": "11002", + "qty": 1, + "productPrice": 4950 }, { - "productId": 11001, - "qty": 1, - "productPrice": 5450 + "productId": "11012", + "qty": 2, + "productPrice": 1195 } ] } @@ -122,7 +123,7 @@ The code that follows shows an example API request and response to create an ord ```json { - "data": "63f5f8dc3696d145a45775a6", // orderId + "data": "d4075f43-c262-4027-ad25-7b1bc8c490b6", //orderId "error": null } ``` @@ -130,33 +131,42 @@ The code that follows shows an example API request and response to create an ord When you make a request, it goes through the API gateway to the `orders service`. Ultimately, it ends up calling a `createOrder` function which looks as follows: ```typescript title="server/src/services/orders/src/service-impl.ts" -async function createOrder(order: IOrder) { +const createOrder = async ( + order: IOrder, + //... +) => { if (!order) { throw 'Order data is mandatory!'; } + const userId = order.userId || USERS.DEFAULT; // Used as a shortcut, in a real app you would use customer session data to fetch user details + const orderId = uuidv4(); + + order.orderId = orderId; order.orderStatusCode = ORDER_STATUS.CREATED; - order.userId = USERS.DEFAULT; // Used as a shortcut, in a real app you would use customer session data to fetch user details - order.createdOn = new Date(); - order.createdBy = order.userId; - order.lastUpdatedOn = null; - order.lastUpdatedBy = null; + order.userId = userId; + order.createdBy = userId; order.statusCode = DB_ROW_STATUS.ACTIVE; + order.potentialFraud = false; order = await validateOrder(order); - const orderId = await addOrderToRedis(order); - order.orderId = orderId; + const products = await getProductDetails(order); + addProductDataToOrders(order, products); + + await addOrderToRedis(order); + + await addOrderToPrismaDB(order); - await addOrderToMongoDB(order); + //... return orderId; -} +}; ``` :::info -For tutorial simplicity, we add data to both MongoDB and Redis in the same service (double-write). As mentioned earlier, a common pattern is to have your services write to one database, and then separately use a CDC mechanism to update the other database. For example, you could write directly to Redis, then use **RedisGears** to handle synchronizing Redis and MongoDB in the background. For the purposes of this tutorial, we don’t outline exactly how you might handle synchronization, but instead focus on how the data is stored and accessed in Redis. +For tutorial simplicity, we add data to both primary database and Redis in the same service (double-write). As mentioned earlier, a common pattern is to have your services write to one database, and then separately use a CDC mechanism to update the other database. For example, you could write directly to Redis, then use **RedisGears** to handle synchronizing Redis and primary database in the background. For the purposes of this tutorial, we don't outline exactly how you might handle synchronization, but instead focus on how the data is stored and accessed in Redis. ::: @@ -169,40 +179,58 @@ If you're using **Redis Enterprise**, you can take advantage of the **integrated Note that in the previous code block we call the `addOrderToRedis` function to store orders in Redis. We use [Redis OM for Node.js](https://github.com/redis/redis-om-node) to store the order entities in Redis. This is what that function looks like: ```typescript title="server/src/services/orders/src/service-impl.ts" -import { Entity, Schema } from 'redis-om'; -import { getRedisOmClient } from '../utils/redis/redis-wrapper'; - -class OrderEntity extends Entity {} - -const schema = new Schema(OrderEntity, { - orderId: { type: 'string' }, - userId: { type: 'string' }, - orderStatusCode: { type: 'number' }, - - productsStr: { type: 'string' }, - - createdOn: { type: 'date' }, - createdBy: { type: 'string' }, - lastUpdatedOn: { type: 'date' }, - lastUpdatedBy: { type: 'string' }, - statusCode: { type: 'number' }, +import { Schema, Repository } from 'redis-om'; +import { getNodeRedisClient } from '../utils/redis/redis-wrapper'; + +//Redis Om schema for Order +const schema = new Schema('Order', { + orderId: { type: 'string', indexed: true }, + + orderStatusCode: { type: 'number', indexed: true }, + potentialFraud: { type: 'boolean', indexed: false }, + userId: { type: 'string', indexed: true }, + + createdOn: { type: 'date', indexed: false }, + createdBy: { type: 'string', indexed: true }, + lastUpdatedOn: { type: 'date', indexed: false }, + lastUpdatedBy: { type: 'string', indexed: false }, + statusCode: { type: 'number', indexed: true }, }); -async function addOrderToRedis(order: IOrder) { - let orderId = ''; - - const redisOmClient = getRedisOmClient(); - const repository = redisOmClient.fetchRepository(schema); - const entity = repository.createEntity(order); +//Redis OM repository for Order (to read, write and remove orders) +const getOrderRepository = () => { + const redisClient = getNodeRedisClient(); + const repository = new Repository(schema, redisClient); + return repository; +}; + +//Redis indexes data for search +const createRedisIndex = async () => { + const repository = getRepository(); + await repository.createIndex(); +}; + +const addOrderToRedis = async (order: OrderWithIncludes) => { + if (order) { + const repository = getOrderRepository(); + //insert Order in to Redis + await repository.save(order.orderId, order); + } +}; +``` - orderId = entity.entityId; - entity.orderId = orderId; +Sample **Order** view using [RedisInsight](https://redis.com/redis-enterprise/redis-insight/) - await repository.save(entity); +sample order - return orderId; -} -``` +:::tip +Download [**RedisInsight**](https://redis.com/redis-enterprise/redis-insight/) to view your Redis data or to play with raw Redis commands in the workbench. Learn more by reading the [**RedisInsight tutorial**](/explore/redisinsight/) +::: ### Order history API @@ -220,67 +248,53 @@ The code that follows shows an example API request and response to get a custome { "data": [ { - "orderId": "01GTH7JTQWP5QSEY32NNKT6B88", - "userId": "ADMIN", - "orderStatusCode": 1, + "orderId": "d4075f43-c262-4027-ad25-7b1bc8c490b6", + "userId": "USR_22fcf2ee-465f-4341-89c2-c9d16b1f711b", + "orderStatusCode": 4, "products": [ { - "productId": 11000, - "qty": 10, - "productPrice": 3995, + "productId": "11002", + "qty": 1, + "productPrice": 4950, "productData": { - "id": 11000, - "price": 3995, - "productDisplayName": "Puma Men Slick 3HD Yellow Black Watches", - "variantName": "Slick 3HD Yellow", + "productId": "11002", + "price": 4950, + "productDisplayName": "Puma Men Race Black Watch", + "variantName": "Race 85", "brandName": "Puma", "ageGroup": "Adults-Men", "gender": "Men", "displayCategories": "Accessories", - "styleImages": { - "default": { - "imageURL": "http://cdn_service/images/11000.jpg" - } - }, - "productDescriptors": { - "description": { - "value": "Stylish and comfortable, this motor sport inspired wrist watch from puma is designed with a plastic case and ..." - } - } + "masterCategory_typeName": "Accessories", + "subCategory_typeName": "Watches", + "styleImages_default_imageURL": "http://host.docker.internal:8080/images/11002.jpg", + "productDescriptors_description_value": "

This watch from puma comes in a heavy duty design. The assymentric dial and chunky..." } }, { - "productId": 11001, - "qty": 19, - "productPrice": 5450, + "productId": "11012", + "qty": 2, + "productPrice": 1195, "productData": { - "id": 11001, - "price": 5450, - "productDisplayName": "Puma Men Top Fluctuation Red Black Watches", - "variantName": "Top Fluctuation Red", - "brandName": "Puma", - "ageGroup": "Adults-Men", - "gender": "Men", - "displayCategories": "Accessories", - "styleImages": { - "default": { - "imageURL": "http://cdn_service/images/11001.jpg" - } - }, - "productDescriptors": { - "description": { - "value": "This watch from puma comes in a clean sleek design. This active watch is perfect for urban wear and ..." - } - } + "productId": "11012", + "price": 1195, + "productDisplayName": "Wrangler Women Frill Check Multi Tops", + "variantName": "FRILL CHECK", + "brandName": "Wrangler", + "ageGroup": "Adults-Women", + "gender": "Women", + "displayCategories": "Sale and Clearance,Casual Wear", + "masterCategory_typeName": "Apparel", + "subCategory_typeName": "Topwear", + "styleImages_default_imageURL": "http://host.docker.internal:8080/images/11012.jpg", + "productDescriptors_description_value": "

Composition
Navy blue, red, yellow and white checked top made of 100% cotton, with a jabot collar, buttoned ..." } } ], - "createdOn": "2023-03-02T13:18:31.657Z", - "createdBy": "ADMIN", - "lastUpdatedOn": null, - "lastUpdatedBy": null + "createdBy": "USR_22fcf2ee-465f-4341-89c2-c9d16b1f711b", + "lastUpdatedOn": "2023-07-13T14:11:49.997Z", + "lastUpdatedBy": "USR_22fcf2ee-465f-4341-89c2-c9d16b1f711b" } - //... ], "error": null } @@ -289,43 +303,30 @@ The code that follows shows an example API request and response to get a custome When you make a request, it goes through the API gateway to the `order history service`. Ultimately, it ends up calling a `viewOrderHistory` function, which looks as follows: ```typescript title="server/src/services/order-history/src/service-impl.ts" -async function viewOrderHistory(userId: string) { +const viewOrderHistory = async (userId: string) => { const repository = OrderRepo.getRepository(); - let orders: IOrder[] = []; - - const result = repository + let orders: Partial[] = []; + const queryBuilder = repository .search() .where('createdBy') .eq(userId) .and('orderStatusCode') - .gte(ORDER_STATUS.CREATED) //gte returns CREATED and PAYMENT_SUCCESS + .gte(ORDER_STATUS.CREATED) //returns CREATED and PAYMENT_SUCCESS .and('statusCode') - .eq(DB_ROW_STATUS.ACTIVE) - .return.all(); - - orders = result.map((elm) => { - return { - orderId: elm.orderId, - userId: elm.userId, - orderStatusCode: elm.orderStatusCode, - createdOn: elm.createdOn, - createdBy: elm.createdBy, - lastUpdatedOn: elm.lastUpdatedOn, - lastUpdatedBy: elm.lastUpdatedBy, - } as IOrder; - }); - - return orders; -} + .eq(DB_ROW_STATUS.ACTIVE); + + console.log(queryBuilder.query); + orders = []>await queryBuilder.return.all(); +}; ``` :::info -Note that the `order history service` only needs to go to Redis for all orders. This is because we handle storage and synchronization between Redis and MongoDB within the `orders service`. +Note that the `order history service` only needs to go to Redis for all orders. This is because we handle storage and synchronization between Redis and primary database within the `orders service`. ::: -You might be used to using Redis as a cache and both storing and retrieving stringified JSON values or perhaps hashed values. However, look closely at the code above. In it, we store orders as **JSON** documents, and then use [Redis OM](https://github.com/redis/redis-om-node) to search for the orders that belong to a specific user. Redis operates like a search engine, here, with the ability to speed up queries and scale independently from the primary database (which in this case is MongoDB). +You might be used to using Redis as a cache and both storing and retrieving stringified JSON values or perhaps hashed values. However, look closely at the code above. In it, we store orders as **JSON** documents, and then use [Redis OM](https://github.com/redis/redis-om-node) to search for the orders that belong to a specific user. Redis operates like a search engine, here, with the ability to speed up queries and scale independently from the primary database (which in this case is MongoDB/ Postgressql). ## Ready to use Redis with the CQRS pattern? diff --git a/docs/howtos/solutions/microservices/interservice-communication/index-interservice-communication.mdx b/docs/howtos/solutions/microservices/interservice-communication/index-interservice-communication.mdx index f3e68ed342..9e76f534d9 100644 --- a/docs/howtos/solutions/microservices/interservice-communication/index-interservice-communication.mdx +++ b/docs/howtos/solutions/microservices/interservice-communication/index-interservice-communication.mdx @@ -7,9 +7,9 @@ authors: [prasan, will] --- import Authors from '@theme/Authors'; -import MicroservicesEcommerceDesign from '../common-data/microservices-ecommerce.mdx'; -import MicroservicesArchitectureWithRedis from '../common-data/microservices-arch-with-redis.mdx'; -import SourceCode from '../common-data/microservices-source-code-tip.mdx'; +import MicroservicesEcommerceDesign from '../common-data/microservices-ecommerce-old.mdx'; +import MicroservicesArchitectureWithRedis from '../common-data/microservices-arch-with-redis-old.mdx'; +import SourceCode from '../common-data/microservices-source-code-tip-old.mdx'; import RedisEnterprise from '../common-data/redis-enterprise.mdx'; @@ -92,11 +92,6 @@ Let's outline the streams and events used below: ], "userId": "USR_4e7acc44-e91e-4c5c-9112-bdd99d799dd3", "orderStatusCode": 1, //order created - "createdOn": { - "$date": { - "$numberLong": "1677926697801" - } - }, "createdBy": "USR_4e7acc44-e91e-4c5c-9112-bdd99d799dd3", "statusCode": 1 } @@ -148,7 +143,7 @@ Let's outline the streams and events used below: -## Building an interservice communication application with Redis and MongoDB +## Building an interservice communication application with Redis We use Redis to broker the events sent between the `orders service` and the `payments service`. @@ -381,7 +376,7 @@ It's a best practice to validate all incoming messages to make sure you can work ::: -For the purposes of our application, we make a call to update the order status in both Redis and MongoDB in the same service (For simplicity, we are not using any synchronization technique between databases rather focusing on how the data is stored and accessed in Redis). Another common pattern is to have your services write to one database, and then separately use a CDC mechanism to update the other database. For example, you could write directly to Redis, then use **RedisGears** to handle synchronizing Redis and MongoDB in the background. +For the purposes of our application, we make a call to update the order status in both Redis and primary database in the same service (For simplicity, we are not using any synchronization technique between databases rather focusing on how the data is stored and accessed in Redis). Another common pattern is to have your services write to one database, and then separately use a CDC mechanism to update the other database. For example, you could write directly to Redis, then use **Triggers and Functions** to handle synchronizing Redis and primary database in the background. :::tip diff --git a/docs/howtos/solutions/real-time-inventory/available-to-promise/index-rti-available-to-promise.mdx b/docs/howtos/solutions/real-time-inventory/available-to-promise/index-rti-available-to-promise.mdx index c5e247f1c9..482c15b106 100644 --- a/docs/howtos/solutions/real-time-inventory/available-to-promise/index-rti-available-to-promise.mdx +++ b/docs/howtos/solutions/real-time-inventory/available-to-promise/index-rti-available-to-promise.mdx @@ -22,6 +22,8 @@ import GeneralAdditionalResources from '../common-rti/additional-resources.mdx'; + + ## What is available-to-promise (ATP)? The major requirement in a **retail inventory system** is presenting an accurate, real-time view of inventory to shoppers and store associates enabling buy-online-pickup-in-store (BOPIS). Optimizing fulfillment from multiple inventory locations.