Node.js Client
This guide provides the basic steps you should follow to set up a NCache Node.js client on Windows, for Data Caching, Tags, SQL, and Events.
Prerequisites
Before proceeding, ensure your environment meets the following requirements:
- Existing Cache: A running cache (e.g.,
demoCache) must already be created on an NCache server. - Node.js Runtime: Version 18.12.0 (or later compatible LTS version). For all supported Node.js versions, refer to Supported Node.js Versions.
- NCache Installation: You must have NCache Enterprise installed on your cache servers. For the client machine, you only need the client libraries.
- Cache Connectivity: Ensure network access to the cache servers (IP address and port, typically 9800).
- Data being cached is serializable.
- Exception handling is in place as described in Handling Failures.
Install Client (Optional)
If your application runs on a machine that does not have a full NCache setup, you can install the NCache Client separately.
NCache provides a Windows Installer (.msi) with which you can install NCache through command line silent mode.
Search for Command Prompt on the Windows Start menu. Right-click on the search result Command Prompt, and select Run as Administrator.
You can install either Cache Server, Developer/QA, or Remote Client. For instance, for Remote Client mode, set the
InstallMode=3in the following command:
msiexec.exe /I "C:\NCacheSetupPath\ncache.ent.net.x64.msi" INSTALLMODE=3 /qn
Setup Node.js Client
Install and include the following module in your Node.js client application, i.e., ncache-client, as follows:
npm install ncache-client
Code Samples
Next, you need to connect to a cache and implement the following features as you see fit.
Data Caching
This example shows how to perform basic CRUD operations using the Node.js client for NCache in a single code sample. It connects to a cache, creates a Product object, and adds it using a CacheItem with a 5-minute sliding expiration so it expires if not accessed. The item is then retrieved and deserialized, updated locally and written back using insert (which overwrites existing data), and finally removed from the cache, demonstrating the full lifecycle of storing, reading, updating, and deleting data along with exception handling.
const ncache = require('ncache-client');
async function main() {
try {
const cacheName = "demoCache";
console.log("Connecting to cache: " + cacheName + "\n");
const connectionOptions = new ncache.CacheConnectionOptions();
const servers = [
new ncache.ServerInfo("server1", "127.0.0.1", 9800)
];
connectionOptions.setServerList(servers);
// Connect to the cache and return a cache handle
const cache = await ncache.CacheManager.getCache("demoCache", connectionOptions);
console.log("Connected to Cache successfully: " + cacheName + "\n");
// Add product 12001 to the cache with a 5-min expiration
const prod1 = new Product('12001', 'Laptop', 1000, 'Electronics');
const prod1Key = prod1.productId.toString();
let expiration = new ncache.Expiration(ncache.ExpirationType.Sliding, new ncache.TimeSpan(0, 0, 5));
var productCacheItem = new ncache.CacheItem(prod1, Product.name);
productCacheItem.setExpiration(expiration);
// Add to the cache with 5min sliding expiration
await cache.add(prod1Key, productCacheItem);
console.log("Product 12001 added successfully (5min expiration):");
printProductDetails(prod1);
// Get from the cache. If not found, a null is returned
var retrievedprod1 = await cache.getCacheItem(prod1Key);
var product = retrievedprod1.getValue(ncache.JsonDataType.Object);
if (product != null) {
console.log("Product 12001 retrieved successfully:");
printProductDetails(product);
}
product.price = 3000;
// Update product in the cache. If not found, it is added
productCacheItem = new ncache.CacheItem(product, Product.name);
productCacheItem.setExpiration(expiration);
await cache.insert(prod1Key, productCacheItem);
console.log("Price for Product 12001 updated successfully:");
printProductDetails(product);
// Remove the item from the cache
await cache.remove(prod1Key, ncache.JsonDataType.Object);
console.log("Deleted the product "+ prod1Key + " from the cache...\n");
console.log("Sample completed successfully.");
await cache.close();
} catch (error) {
console.error('Error:', error);
} finally {
process.exit();
}
}
function printProductDetails(product) {
console.log("ProductID, Name, Price, Category");
console.log(`- ${product.productId}, ${product.name}, ${product.price}, ${product.category} \n`);
}
class Product {
constructor(id, name, price, category) {
this.productId = id;
this.name = name;
this.price = price;
this.category = category;
}
}
main();
Tags
Similarly, if you want to label and categorize the data you are caching you can use the following code. It demonstrates how to use Tags in NCache to logically group and retrieve related cache items. It creates several Product objects and wraps each in a CacheItem, assigning one or more tags (such as "Technology", "Reading", or "Communication") using setTags, which allows items to be categorized independent of their keys.
After adding all items to the cache, the code uses the SearchService to fetch keys associated with a specific tag (e.g., "Technology"), then retrieves the actual objects using those keys and printing their details. Then, the code removes the tags in bulk by creating a list of tags and calling removeByTags with the ByAnyTag option, thus, deleting all items that match any of the specified tags. This demonstrates how tags enable efficient grouping, querying, and batch operations without the user needing to know individual cache keys.
...
async function main() {
try {
...
var laptop = new Product ( "12001", "Laptop", 2000, "Electronics" );
var kindle = new Product ( "12002", "Kindle", 1000, "Electronics" );
var book = new Product ( "12003", "Book", 100, "Stationery" );
var smartPhone = new Product ( "12004", "Smart Phone", 1000, "Electronics" );
var mobilePhone = new Product ( "12005", "Mobile Phone", 200, "Electronics" );
var laptopCacheItem = new ncache.CacheItem(laptop, Product.name);
laptopCacheItem.setTags([new ncache.Tag("Technology"), new ncache.Tag("Gadgets")]);
var kindleCacheItem = new ncache.CacheItem(kindle, Product.name);
kindleCacheItem.setTags([new ncache.Tag("Technology"), new ncache.Tag("Reading")]);
var bookCacheItem = new ncache.CacheItem(book, Product.name);
bookCacheItem.setTags([new ncache.Tag("Education"), new ncache.Tag("Reading")]);
var smartPhoneCacheItem = new ncache.CacheItem(smartPhone, Product.name);
smartPhoneCacheItem.setTags([new ncache.Tag("Technology"), new ncache.Tag("Communication")]);
var mobilePhoneCacheItem = new ncache.CacheItem(mobilePhone, Product.name);
mobilePhoneCacheItem.setTags([new ncache.Tag("Technology"), new ncache.Tag("Communication")]);
const products = {
"12001": laptopCacheItem,
"12002": kindleCacheItem,
"12003": bookCacheItem,
"12004": smartPhoneCacheItem,
"12005": mobilePhoneCacheItem
};
// Add all the products to the cache.
for (const [key, value] of Object.entries(products)) {
await cache.add(key, value);
}
console.log("Products added to the cache successfully.\n");
const searchService = await cache.getSearchService();
const technologyItems = await searchService.getKeysByTag("Technology");
console.log("Got Items from the cache by Tag \"Technology\"");
printProductDetails(await getItemsByKeys(technologyItems, cache));
// Get all items from the cache with this Tag. readingItems is a list of key-value pairs
var readingItems = await searchService.getKeysByTag("Reading");
console.log("Got the Items from the cache by Tag \"Reading\"");
printProductDetails(await getItemsByKeys(readingItems, cache));
// Create an array of tags
const tags = [new ncache.Tag("Technology"), new ncache.Tag("Reading")];
// Remove all items from the cache with any of the tags
await searchService.removeByTags(tags, ncache.TagSearchOptions.ByAnyTag);
console.log("Removed Items by Tags \"Technology\" and \"Reading\"\n");
console.log("Sample completed successfully.");
} catch (error) {
console.error('Error:', error);
} finally {
process.exit();
}
}
async function getItemsByKeys(products, cache) {
const fetchedProducts = {};
for (const product of products) {
const cacheItem = await cache.getCacheItem(product);
fetchedProducts[product] = cacheItem.getValue(ncache.JsonDataType.Object);
}
return fetchedProducts;
}
function printProductDetails(items) {
const mapItems = new Map(Object.entries(items));
if (mapItems && mapItems.size > 0) {
console.log("ProductID, Name, Price, Category");
mapItems.forEach(cacheItem => {
const product = cacheItem;
console.log(`- ${product.productId}, ${product.name}, $${product.price}, ${product.category}`);
});
} else {
console.log("No items found...");
}
console.log();
}
...
SQL
This code shows how to use a NCache like a database. First, it adds sample products into the cache with categories and tags, which are indexed for searching (after indexing is configured using the NCache Management Center or the Add-QueryIndex cmdlet). Then, it runs different SQL-like queries: one filters products by category and price, another uses a LIKE condition and tags to find specific items, and a third groups products by category to count them. After displaying results, it deletes items based on certain tags. Overall, it demonstrates storing, querying, grouping, and deleting cached data using asynchronous operations.
...
async function main() {
try {
...
await AddSampleData(cache);
console.log("Find products with Category IN (\"Electronics\", \"Stationery\") AND Price < $2000")
// $VALUE$ keyword means the entire object instead of individual attributes that are also possible
var sql = "SELECT $VALUE$ FROM __main__.Product WHERE category IN ('Electronics', 'Stationery') AND price < ?";
var sqlCommand = new ncache.QueryCommand(sql);
let parametersMap = new Map();
parametersMap.set("price", 2000);
sqlCommand.setParameters(parametersMap);
cacheReader = await cache.getSearchService().then(searchService => searchService.executeReader(sqlCommand));
var fetchedProducts = [];
if (cacheReader.getFieldCount() > 0) {
while (await cacheReader.read()) {
const result = cacheReader.getValue(1,ncache.JsonDataType.Object);
fetchedProducts.push(result)
}
}
PrintProducts(fetchedProducts);
console.log("Find all \"phone\" products (using LIKE operator) AND (Tag = \"Technology\" OR Tag = \"Gadgets\")");
sql = "SELECT $VALUE$ FROM __main__.Product WHERE name LIKE ? AND ($Tag$ = 'Technology' OR $Tag$ = 'Gadgets')";
sqlCommand = new ncache.QueryCommand(sql);
parametersMap = new Map();
parametersMap.set("name", "*Phone*" )
sqlCommand.setParameters(parametersMap);
cacheReader = await cache.getSearchService().then(searchService => searchService.executeReader(sqlCommand));
fetchedProducts = [];
if (cacheReader.getFieldCount() > 0) {
while (await cacheReader.read()) {
const result = cacheReader.getValue(1,ncache.JsonDataType.Object);
fetchedProducts.push(result)
}
}
PrintProducts(fetchedProducts);
console.log("GROUP BY query: Get a count of product by category with Price < $3000");
sql = "SELECT category, COUNT(*) FROM __main__.Product WHERE price < ? GROUP BY category";
sqlCommand = new ncache.QueryCommand(sql);
parametersMap = new Map();
parametersMap.set("price", 3000)
sqlCommand.setParameters(parametersMap);
cacheReader = await cache.getSearchService().then(searchService => searchService.executeReader(sqlCommand));
if (cacheReader.getFieldCount() > 0) {
while (await cacheReader.read()) {
const category = cacheReader.getValue(0, ncache.JsonDataType.Object);
const count = cacheReader.getValue(1, ncache.JsonDataType.Object);
console.log("- " + category + ", " + count);
}
}
console.log("\nDelete Items by Tags \"Technology\" and \"Reading\"");
parametersMap = new Map();
parametersMap.set("$Tag$", "Technology")
sql = "DELETE FROM __main__.Product WHERE $Tag$ IN ('Technology', 'Reading')";
sqlCommand = new ncache.QueryCommand(sql);
const itemAffected = await cache.getSearchService().then(searchService => searchService.executeNonQuery(sqlCommand));
console.log(itemAffected + " items removed from the cache.\n");
console.log("Sample completed successfully.");
} catch (error) {
console.error('Error:', error);
} finally {
process.exit();
}
}
async function AddSampleData(cache) {
console.log("Adding products to the cache with tags...");
var laptop = new Product ( "13001", "Laptop", 2000, "Electronics" );
var kindle = new Product ( "13002", "Kindle", 1000, "Electronics" );
var book = new Product ( "13003", "Book", 100, "Stationery" );
var smartPhone = new Product ( "13004", "Smart Phone", 1000, "Electronics" );
var mobilePhone = new Product ( "13005", "Mobile Phone", 200, "Electronics" );
var laptopCacheItem = new ncache.CacheItem(laptop, "__main__.Product");
laptopCacheItem.setTags([new ncache.Tag("Technology"), new ncache.Tag("Gadgets")]);
var kindleCacheItem = new ncache.CacheItem(kindle, "__main__.Product");
kindleCacheItem.setTags([new ncache.Tag("Technology"), new ncache.Tag("Reading")]);
var bookCacheItem = new ncache.CacheItem(book, "__main__.Product");
bookCacheItem.setTags([new ncache.Tag("Education"), new ncache.Tag("Reading")]);
var smartPhoneCacheItem = new ncache.CacheItem(smartPhone, "__main__.Product");
smartPhoneCacheItem.setTags([new ncache.Tag("Technology"), new ncache.Tag("Communication")]);
var mobilePhoneCacheItem = new ncache.CacheItem(mobilePhone, "__main__.Product");
mobilePhoneCacheItem.setTags([new ncache.Tag("Technology"), new ncache.Tag("Communication")]);
const products = {
"13001": laptopCacheItem,
"13002": kindleCacheItem,
"13003": bookCacheItem,
"13004": smartPhoneCacheItem,
"13005": mobilePhoneCacheItem
};
// Adds all the products to the cache. This automatically creates indexes on various
// attributes of Product object by using "Custom Attributes".
for (const key in products) {
if (products.hasOwnProperty(key)) {
await cache.insert(key, products[key]);
}
}
const productValues = Object.values(products).map(cacheItem => cacheItem.getValue(ncache.JsonDataType.Object));
PrintProducts(productValues);
}
function PrintProducts(products) {
console.log("ProductID, Name, Price, Category");
for (const product of products) {
console.log(`- ${product.productID}, ${product.name}, $${product.price}, ${product.category}`);
}
console.log();
}
...
/*
{
"objects":
[
{
"$Index_Class$": "__main__.Product",
"name" : "Dairy Milk Cheese",
"category" : "Edibles",
"price":12
}
]
}
*/
Events
This example demonstrates how to use Events in NCache with a Node.js client to get notified when changes occur in the cache. You can subscribe to cache-level events such as item added, updated, or removed, allowing your application to react in real time without polling.
The code below registers event listeners, performs cache operations, and shows how the events are triggered automatically.
...
async function main() {
try {
...
// Register cache-level event listeners
cache.addCacheDataModificationListener(async (key, eventArgs) => {
console.log(`Cache event received for key: ${key}`);
console.log(`Event Type: ${eventArgs.getEventType()}\n`);
});
// Create sample product
const product = new Product("20001", "Headphones", 500, "Electronics");
const key = product.productId.toString();
const cacheItem = new ncache.CacheItem(product, Product.name);
// Add item (triggers ItemAdded event)
await cache.add(key, cacheItem);
console.log("Item added to cache.\n");
// Update item (triggers ItemUpdated event)
product.price = 700;
const updatedItem = new ncache.CacheItem(product, Product.name);
await cache.insert(key, updatedItem);
console.log("Item updated in cache.\n");
// Remove item (triggers ItemRemoved event)
await cache.remove(key, ncache.JsonDataType.Object);
console.log("Item removed from cache.\n");
console.log("Event sample completed successfully.");
await cache.close();
} catch (error) {
console.error("Error:", error);
} finally {
process.exit();
}
}
...
See Also
Installation Guide
Developer's Guide
Node.js Sessions
Administrator's Guide