There are many methods to query data from CMS in Wix. You can use datasets without writing any line of code or query or aggregate data with code. Data aggregation allows populating a group of categorized data with code whereas data query is just a regular query for the same data.
In this tutorial, we will be showing you how to use Wix data aggregate() method to query data from CMS by digging a project built in Wix Studio.
Project Summary
The only page contains a table that was built using a repeater and its elements as well as static text elements around.
We create a CMS collection to store data for "title" and "quoteId"
We upload a file from the "upload page" and then insert data to the CMS (these are the steps not shown)
Then, perform a data aggregation to retreive data from CMS.
Your code playground will be limited to one page for performing data aggregation.
If you are totally new to Velo coding, try to learn and practice Velo functions and features first.
What Is Data Aggregation?
Data aggregation is a process to create a subgroup of data from a collection in Wix CMS (content management system) in Wix Velo.
You simply query data from CMS and then populate data for UI from the object returned.
You stack data with keywords inside the aggregation chain and consume it when it is called by the page or a file.
How to Perform Data Aggregation?
In this Velo project, we had a CMS data collection called quoteFiles which we use to insert files and other specifications on front-end. It simply takes all uploaded files and assign them to the same quote ID every time a user starts uploading files from the upload page.
See repeated quoteIDs below.
So, create a data collection in Wix with the field IDs "title" and "quoteId" and add some sample data
What we would like to manage is populating a repeater data on admin page after we query all quotes with their unique IDs and count how many files are assigned to each quote ID.
You can see the final result below to get to the point before sharing more details and step by step code.
Create backend files and functions
We will create two backend files ("manage.js" and "app.js") and define our functions to secure any data process.
Using js files prevent someone who is not granted with a permission on CMS to reach your backend data and perform any operation on front-end.
The first file is we create is manage.js. This file is responsible of aggregating data and returning the results if there are any.
export async function getDistinct () {
const results = await wixData.aggregate("quoteFiles").group("quoteId").limit(100).count().run();
if (results.items.length > 0) {
return results.items;
}
}
Like all backend functions, getDistinct() should also be exported. So, while we are defining this function, we define it like this:
export async function getDistinct () {
}
Now, we need to aggregate data after a chain of data operations and then assign the result to a variable.
const results = await wixData.aggregate("quoteFiles").group("quoteId").limit(100).count().run();
We group our data based on "quoteId"s and count how many row each group include.
Similar to a data query, we can perform data chain operations on aggregations but there is a trip you can't ignore. When you perform a chain, the aggregation result object contains the terminations you defined on that chain.
For this example, it is:
The _id is automatically retrieved whereas count and quoteId is defined in aggregation chain.
At the end, if there is a result, we return the function to that result.
if (results.items.length > 0) {
return results.items;
}
Now, we need to define our second back-end file app.web.js. web.js files can be accessed from front-end so you can import the functions defined in web.js files to your page code.
import { Permissions, webMethod } from "wix-web-module";
import * as app from 'backend/files/manage.js';
export const getDistinct = webMethod(
Permissions.Anyone,
() => {
return app.getDistinct();
})
getDistinct() function retreives and returns to the results returned from the function defined in manage.js file. It overrides the permissions to surpass any restriction.
Write front-end code for page interaction
For page interaction, we first add a repeater on admin page (not admin dashboard, just a page for a special case) and add two text elements to connect them to the associated fields from aggregation result.
quoteId text --> quoteId
quantity text --> count
Take a look at the page code.
//-------------Imports-------------//
import * as app from 'backend/files/app.web.js';
//-------------Global Variables-------------//
const repeater = $w('#repeater');
const quoteTitle = $w('#quoteTitle');
$w.onReady(async function () {
repeater.data = [];
await getItems();
registerHandlers();
});
function registerHandlers() {
repeater.onItemReady(($item, itemData) => {
$item('#quoteId').text = itemData.quoteId;
$item('#quantity').text = `${itemData.count}`;
});
}
// gets aggregated data from the CMS with a backend function
async function getItems() {
try {
const result = await app.getDistinct();
repeater.data = result;
console.log("repeater data: ", repeater.data);
quoteTitle.text = `Quote Requests (${repeater.data.length})`;
} catch (error) {
console.error(error);
}
}
Try to understand the code step by step.
First, we import our function from app.web.js file.
//-------------Imports-------------//
import * as app from 'backend/files/app.web.js';
Then, assign global variables to page elements.
//-------------Global Variables-------------//
const repeater = $w('#repeater');
const quoteTitle = $w('#quoteTitle');
Then, we call the function from the page and populate repeater data.
// gets aggregated data from the CMS with a backend function
async function getItems() {
try {
const result = await app.getDistinct();
repeater.data = result;
console.log("repeater data: ", repeater.data);
quoteTitle.text = `Quote Requests (${repeater.data.length})`;
} catch (error) {
console.error(error);
}
}
Then, we connect repeater element to the data assigned to the repeater. If it is the first time you try to populate repeater data, you can start populating a repeater with static data.
function registerHandlers() {
repeater.onItemReady(($item, itemData) => {
$item('#quoteId').text = itemData.quoteId;
$item('#quantity').text = `${itemData.count}`;
});
}
And, finally, we call all function from onPageReady function so that all functions will be called once the page elements are ready.
$w.onReady(async function () {
repeater.data = [];
await getItems();
registerHandlers();
});
Pay attention to the async-await pairs which are used to run the function asynchronously.
Resources
Wix Velo Aggregate API: https://dev.wix.com/docs/velo/api-reference/wix-data/aggregate
If you have further questions or a point that you need to understand better, you can leave a comment beneath this post.
Comments