Initial commit

Co-Authored-By: kotte <14197736+mrtamagotchi@users.noreply.github.com>
Co-Authored-By: mikaeltellhed <2311083+mikaeltellhed@users.noreply.github.com>
Co-Authored-By: Tore Knudsen <18231882+torekndsn@users.noreply.github.com>
Co-Authored-By: Michael Cartner <32543275+michaelcartner@users.noreply.github.com>
This commit is contained in:
Eric Tuvesson
2023-09-05 12:08:55 +02:00
commit 53f0d6320e
2704 changed files with 76354 additions and 0 deletions

View File

@@ -0,0 +1,207 @@
---
title: Access Control
hide_title: true
---
# Access Control
## What you will learn in this guide
By now you should have a good understanding of how to create, update and query records in the database. If you feel the need to freshen up your skills, check out there guides.
- [Creating a Backend](/docs/guides/cloud-data/creating-a-backend)
- [Creating a Class](/docs/guides/cloud-data/creating-a-class)
- [Creating Records](/docs/guides/cloud-data/creating-new-database-records)
- [Record Relations](/docs/guides/cloud-data/record-relations)
By default all records you create are completely public, so they can be read and written by any user, logged in or anonymous. This is ok while you are developing your application but as soon as it is getting ready to be released outside of your team you will need to think about access control. That is who should be able to read and write which records. Fortunately there is a pretty solid way of achieving this in Noodl.
In this guide you will learn how to limit access control to records you create to certain users.
## Class Level Permissions
There are two levels you can specify access control to your cloud data, either **Class Level Permissions** that are the same for every record of a certain class, and the **Access Control Rules** which apply to a specific record only. Let's start with the former. You can access **Class Level Permissions** for a specific class via the cloud services dashboard.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/access-control/clp-1.png)
</div>
This will bring up the following popup.
<div className="ndl-image-with-background xl">
![](/docs/guides/cloud-data/access-control/clp-2.png)
</div>
Here you can control the **Read**, **Write** and **Add Field** (the possibility to modify the properties for a class) permissions for a specific class. You can enable and disable them for:
* **Public** These are user of your application that is not signed in. So this means anyone, public, can perform these actions on records in this class. By default all operations, reading, writing and modyfing the fields are completely public.
* **Authenticated** This refers to users that have been signed up and logged in to your application. Again, this applies to all records of this class.
In the example below permissions are set so that everyone can read records in this class (this also include querying) but only logged in users can write (create new and modify) and no one (except when using the dashboard of course) can modify the properties of this class.
<div className="ndl-image-with-background xl">
![](/docs/guides/cloud-data/access-control/clp-3.png)
</div>
You can specify a little bit more detailed access control using **Class Level Permissons** with roles and pointers. First just as you specified access for public vs authenticated users you can specify access for users belonging to a certain role (more on roles below). For that you use the text input at the bottom of the list:
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/access-control/clp-4.png)
</div>
You simply type `role:the-name-of-your-role` and then provide the permissions for that role. With this approach you could for instance have a role named `admin` and you could have special permissions for any users having that role. In the example below records of this class have public read access, but only users belonging to the role `admin` can modify records.
<div className="ndl-image-with-background xl">
![](/docs/guides/cloud-data/access-control/clp-5.png)
</div>
You can use the `Simple / Advanced` switch at the top right to enable even more fine grained control. This will be very useful for some use cases. Now permissions are split up into:
* `Get` If you have an **Id** of a record, this permission allows the user to get the properties of the record.
* `Find` Records of this class will show up in a [Query Records](/nodes/data/cloud-data/query-records), this permission makes all records of this class readable.
* `Count` You can perform a count on this class, but directly read all records.
* `Create` Permission to create new records.
* `Update` Permission to update existing records.
* `Delete` Permission to delete existing records.
* `Add Field` Permission to modify the properties of this class, remove/add entire properties.
<div className="ndl-image-with-background xl">
![](/docs/guides/cloud-data/access-control/clp-6.png)
</div>
Another way to specify more detailed access control is using pointers. So let's say you have a record class `Post` that contain blog posts. Now you want everyone to be able to read the records, but only the creator of the `Post` record should be able to modify it. If you add a pointer to a `User` record on your `Post` class (it must be a pointer to a `User`) you can specify permissions for the user that the pointer points to. Let's say you have a pointer on your class called `Owner` that you set to the current user when creating a post, you could then have an access control that looks like this.
<div className="ndl-image-with-background xl">
![](/docs/guides/cloud-data/access-control/clp-7.png)
</div>
With **Class Level Permissions** you can specify access control down to a certain level, but all permissons are still on a class level which means they apply equally to all records of the class. Using **Access Control Rules** you can provide even more detailed permissions, read more about it below.
## Access Control Rules
You can set the access conrol of a record when it is created with the **Create New Record** node or, you can update it later usign the **Set Record Properties** node. This is done using the access control rules part in the property panel. Here is an example below.
<div className="ndl-image-with-background m">
![](/docs/guides/cloud-data/access-control/acl-1.png)
</div>
But when you place a new **Create New Record** node and view the properties the rules will be empty. You can create a new rule by clicking the **(+)** icon.
<div className="ndl-image-with-background m">
![](/docs/guides/cloud-data/access-control/acl-empty.png)
![](/docs/guides/cloud-data/access-control/acl-first.png)
</div>
You can have how every many access control rules you want and each rule has a specific **Target** that you need to pick:
- **User** (default) this indicates that this rule will target a specific user. You can provide the user by connection to the **User Id** input for the rule (this is only available if you have choosen the **User** target). Or if you don't explicitly provide a user id the current logged in user will be used.
- **Everyone** this implies that the rule will target all users, logged in or anonymous. This can be used to create public but read only records.
- **Role** this target should be used if you want this record to be accessible by a group of users. We will take a closer look at roles below.
First let's take a look at a common rule where we make sure the user creating the record has access rights to reading and writing the record.
<div className="ndl-image-with-background m">
![](/docs/guides/cloud-data/access-control/acl-creator.png)
</div>
This is simply the default settings for the rule. It is recommended that you edit the label of the rule and give it a short descriptive name so that you know later what it is supposed to achieve. Ok so if we use this rule to create records only the current user will be able to access them. This requires that a user has been [logged in](/nodes/data/user/log-in/).
Now let's say that we also want everyone to be able to read the records but not change them. Then we would add a rule with the **Everyone** target.
<div className="ndl-image-with-background m">
![](/docs/guides/cloud-data/access-control/acl-public-read.png)
</div>
There are many ways you can use this pattern to control who can access your record. Let's say you are creating a **Message** record and you want the current users (the sender) to be able to read and write the message, and the receiver to be able to read it. You would use a very similar set of rules but with two **User** targets.
<div className="ndl-image-with-background m">
![](/docs/guides/cloud-data/access-control/acl-msg-1.png)
</div>
But you will also need to provide the **User Id** of the receiver (the sender will user the current logged in user). This is done via a connection to the **User Id** input that is created when you add a new **User** target rule.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/access-control/acl-msg-2.png)
</div>
## Roles
This is great, but sometimes you want to have a record accessible by many users and if these users change over time it's a hazzle to update all records accordingly. This is where roles come in. A role is in it's essence simply a list of users (this is esstablished via a relation property called **users** on the role). You can add and remove users from the role using the **Add Record Relation** and **Remove Record Relation** nodes. You can add a role via the cloud services dashboard.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/access-control/acl-role-1.png)
![](/docs/guides/cloud-data/access-control/acl-role-2.png)
</div>
You need to provide a **Name** for your role (this needs to be unique among all roles), you also need to specify the **ACL** (the access control) and you should generally limit it to **Master Key Only** for roles that you create in the dashboard. Once the role is created you can add users to it via the **User** relation directly in the dashboard.
Once you have a role in place with users assiged to it you can simply create a **Role** access rule:
<div className="ndl-image-with-background m">
![](/docs/guides/cloud-data/access-control/acl-role-3.png)
</div>
You choose the **Role** target, give it a descriptive label and choose the access rights. Then you need to specify the **Role Name**, that is the unique name you gave the role when creating it. This is case sensitive.
Most cases you want to create and manage your roles dynamically, for instance if you want to create a team of users that should have access to certain records. Then you would create a role for that team and add relations to all team members.
This is achieved by creating a new role, which is done as any other record with the **Create New Record** node, picking the **Role** class. You need to limit the access control of the **Role** otherwise it will not succeed to create. Here we let the creater, i.e. the current user have full access and also we grant access to "everyone in the team". This is done via the role name, that is the same name as we give the role when creating it (we provide that via a connection as shown below).
<div className="ndl-image-with-background m">
![](/docs/guides/cloud-data/access-control/acl-create-role-1.png)
</div>
You need to provide a unique **name** for your new role, in the example below this is simply done with the **Unique Id** node. This is provided both to the **name** input for the role and also to the **Everyoone in Team** access rule as described above.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/access-control/acl-create-role-2.png)
</div>
Once the new **Role** is created we add the current logged in user to the role by adding a relation usign the **Add Record Relation** node. The current user already has read and write access to the role via **The creator** rule above, but we still add the user to the role as it should be listed as a team member. This is how we set up the **Add Record Relation** node.
<div className="ndl-image-with-background m">
![](/docs/guides/cloud-data/access-control/acl-create-role-3.png)
</div>
The **Id** is coming from the newly created role (that is the record where we want to add a relation), the class needs to be set to **Role** and the relation we want to add to is **users**.
Finally the **Target Record Id** is the user we want to add to the role and as you an see in the node graph above we get the from the **User** node that contains information on the currently logged in user.

View File

@@ -0,0 +1,118 @@
---
title: Creating a Cloud Service
hide_title: true
---
# Creating a Cloud Service for your project
<div className="ndl-image-with-background xl">
![](/docs/guides/cloud-data/creating-a-backend/dashboard-1.png)
</div>
## What you will learn in this guide
This guide will take you through the process of creating a **Cloud Service** for your Noodl project. A **Cloud Service** is needed if you want to fetch and store data for you application in a cloud **Database** and if you want to run and deploy **Cloud Functions**.
### Overview
We will go through the following steps in this guide:
- Creating a Cloud Services
- Selecting a Cloud Services for you project
- Inspect the **Cloud Services Database** using the **Dashboard**
- Create and switch to a new **Cloud Service**
## What is a Cloud Service and when do you need it?
A **Cloud Service** is a piece of software running in the cloud that helps serving your Noodl app with data and cloud functionality. The main reason for using a **Cloud Service** in your project is to use its **Database**. For example the nodes [Record](/nodes/data/cloud-data/record) and [Query Records](/nodes/data/cloud-data/query-records) can only be used if you have a **Cloud Service** active for you project. Also you need them for running [Cloud Functions](/docs/guides/cloud-logic/introduction).
Each **Cloud Service** has a dedicated database which means you might want to have multiple **Cloud Services** available for your project, for example one for your test data and one for your production data. Only one **Cloud Service** can be active for your project at one time, but when you [Deploy](/docs/guides/deploy/deploying-an-app-on-sandbox) you can choose which service to use for the deploy.
Also note that **Cloud Services** are shared within a workspace, i.e. all projects in a workspace have access to the all **Cloud Services**.
### Noold hosted vs Self Hosted Cloud Services
In Noodl there are two types of **Cloud Services**, **Noodl Hosted (default)** and **Self Hosted**. The **Noodl Hosted** are easiest to use, since Noodl can create those for you in a few clicks. **Self Hosted Cloud Services** are services that you set up and host yourself, check out [this guide](/docs/guides/deploy/using-an-external-backend), In this guide we will focus on **Noodl Hosted Cloud Services**.
To add a new Cloud Service click the **Cloud Services** tab icon in the side bar.
<div className="ndl-image-with-background">
![](/docs/guides/cloud-data/creating-a-backend/cloud-services-tab.png)
</div>
Then click the **Plus** icon at the top of the sidebar.
<div className="ndl-image-with-background">
![](/docs/guides/cloud-data/creating-a-backend/cloud-services-add.png)
</div>
Go to the **Add Cloud Service** tab.
<div className="ndl-image-with-background xl">
![](/docs/guides/cloud-data/creating-a-backend/add-cloud-service.png)
</div>
Give the Cloud Service a name, for example "My Cloud Service" and a description "My cloud service for development". It could be a good idea to have multiple cloud services for the same project, since each cloud service will have its own database. This means that you can have one cloud service for development - where it doesnt matter if you mess up your data - and one for production.
## Select active cloud service
Now you can select the newly created cloud service as the active for your project. In the sidebar, click `Use in editor`.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/creating-a-backend/cloud-service-created.png)
</div>
This means that any data requests, for example from a [Query Records](/nodes/data/cloud-data/query-records), when running in the editor will use this cloud service.
## Inspect the Cloud Service using the Dashboard
Now your project is connected to a **Cloud Service** with a **Database**. The best way to get an overview of the database is to open the **Dashboard**. You open it by clicking the `Open dashboard` button on your Cloud Service.
<div className="ndl-image-with-background xl">
![](/docs/guides/cloud-data/creating-a-backend/dashboard-1.png)
</div>
No you can see the contents of your **Database** in the menu to the left, under `Browser`. Right now, the Database contains two _classes_: `User` and `Role`. These two classes are created automatically. These classes are used to manage login and credentials in your app but we will not care about them in this guide.
### Classes
A **Class** in the database is a collection of **Records** of the same type. In other databases these are often referred to as **Tables** or **Collections**. In the case of the `User` class, it contains **User Records** where each record have data properties such as User Name, Email, etc. A typical app will have many different classes but we will not create any new classes in this guide. Instead you can close the **Dashboard** window for now.
## Creating and switching to a new cloud service
Now you can create a second cloud service, be following the same process as above. Give it a name, for example `Second cloud service` and a short description: `My production service`. You now have a second cloud service in the list, that you can make it the active backend for the editor by clicking `Use in editor`.
<div className="ndl-image-with-background xl">
![](/docs/guides/cloud-data/creating-a-backend/second-backend.png)
</div>
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/creating-a-backend/second-backend-2.png)
</div>
Now you can switch back and forth between your two cloud services. But most often you use one for development and the other when you deploy.
## Deploying with a cloud service
When you deploy you application you pick which cloud service to use for the deploy. So you can for instance have one test deploy to sandbox that is using your development or testing cloud service, and another using your custom domain that use your production cloud service.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/creating-a-backend/deploy.png)
</div>

View File

@@ -0,0 +1,143 @@
---
title: Creating a Database Class
hide_title: true
---
# Creating a Class in the Database
## What you will learn in this guide
In this guide you will learn how to create new **Classes** in the database and add new **Columns** to it. **Classes** are used to hold **Records** in a Database in Noodl.
## Overview
We will go through the following steps in this guide
- Add a new **Class** to the Database using the **Dashboard**
- Add new **Columns** to the Class
- Add a couple of new **Records** in the Class through the **Dashboard**
Before you start this guide, make sure you have enabled Cloud Services and have one active for your project. You can learn how to do this in [this](/docs/guides/cloud-data/creating-a-backend) guide.
## Add a new Class to the database using the **Dashboard**
First, make sure you have an active cloud service for your project. Then click the `Dashboard` button in the Cloud Services sidebar.
<div className="ndl-image-with-background xl">
![](/docs/guides/cloud-data/creating-a-class/dashboard-1.png)
</div>
Now you can add a new Class to the database either by clicking the yellow button `Create a Class` in the menu to the left, or open the `Edit` menu and select `Add a Class`.
<div className="ndl-image-with-background">
![](/docs/guides/cloud-data/creating-a-class/create-class-1.png)
</div>
<div className="ndl-image-with-background m">
![](/docs/guides/cloud-data/creating-a-class/create-class-2.png)
</div>
Next step is to give the **Class** a name. Fill in a name, for example `Task` and make sure it's of the type `Custom`. Now you can select `Create class and add columns`.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/creating-a-class/add-class.png)
</div>
## Adding Columns to a Class
### What is a column?
Each **Class** in Noodl have a number of Columns which defines what type of data each **Record** in the class can have. For example, if you are building a Task Management app, you may have a class called `Task`, with the columns `task` and `isDone` as two columns, holding the description of the task and wether the task is done or not. In Noodl, the **Columns** will be represented as properties on the [Record](/nodes/data/cloud-data/record) node that can be used as inputs our outputs.
<div className="ndl-image-with-background xl">
![](/docs/guides/cloud-data/creating-a-class/class.png)
</div>
<div className="ndl-image-with-background">
![](/docs/guides/cloud-data/creating-a-class/record-1.png)
</div>
<div className="ndl-image-with-background">
![](/docs/guides/cloud-data/creating-a-class/record-2.png)
</div>
:::note
[Relations](/docs/guides/cloud-data/record-relations?id=relation-many-to-many-relationships) are an exception here. They can only be used through Queries and won't shop up as properties on Record nodes.
:::
### Column Types
Each **Column** has a specific data type that decides what kind of data it can hold.
There are 11 different data types available:
- **String** - a string value
- **Boolean** - a boolean value (can be `true` or `false`)
- **Number** - a number value
- **Date** - a date (stored in iso format)
- **Object** - a JavaScript object
- **Array** - a JavasSript array
- **Geopoint** - A Geopoint, i.e. a location on the surface of the earth
- **Polygon** - a GEOJSon polygon object
- **File** - a reference to a file
- **Pointer** - A pointer to another **Record** in a **Class**
- **[Relations](/docs/guides/cloud-data/record-relations?id=relation-many-to-many-relationships)** - A list of relations to other **Records** in a **Class**. Note that these won't show up directly on the **Record** node, but are available in queries.
In this guide, we will focus in on the simpler data types, `String`, `Boolean` and `Number`.
Lets add two columns to our **Class**, `task` - a `String` type column, and `isDone` - a `boolean`. You can also chose to have a default value for each column that will be set if a new **Record** has no entry set for that column. In our case, let set the default value of `isDone` to `false`.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/creating-a-class/add-new-column.png)
</div>
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/creating-a-class/add-new-column-2.png)
</div>
You can also select if a **Column** is required for a new **Record** to be added in the **Class**. If set to `true`, the insertion will any new **Record** that has no value provided for the **Column**. Right now we don't want that, so we will leave it in the state `No` for both **Columns**.
### The default columns
As you can see when inspecting your new Task Class in the **Dashboard**, it also contains a few other **Columns**. These are automatically created you should generally not remove them. They are actually quite useful. The default columns are
- **objectId** - This is a unique identifyer for each **Record**. This identifyer will become the `id` property of the **Record** node when refering to it using a **Record** node.
- **createdAt** - A Date object containing the date and time for when the **Record** was created.
- **updatedAt** - A Date object containing the date and time for when the **Record** was last updated.
- **ACL** - A special column to keep track of which users and roles that has the right to fetch and store this object. For now, lets leave it as it is.
## Adding a new Record
Now it's time to add a new **Record** to the Task Class. You can add **Record** either through the `Add a row`-button or through the `Edit` menu and then selecting `Add row` or `Add row through modal`. Let's click on the latter button. This brings up a form that lets you fill out the values for each **Column** for the new **Record**.
<div className="ndl-image-with-background">
![](/docs/guides/cloud-data/creating-a-class/add-row-1.png)
</div>
<div className="ndl-image-with-background s">
![](/docs/guides/cloud-data/creating-a-class/add-row-2.png)
</div>
Add a few **Records** and see them pop up in the **Class**. You can also try deleting them by selecting them and click `Edit`->`Delete these rows`.

View File

@@ -0,0 +1,128 @@
---
title: Creating new Database Records
hide_title: true
---
# Storing and fetching data in a database
## What you will learn in this guide
In this guide you will learn how to create and insert new entries - **Records** in a cloud database using the
[Create New Record](/nodes/data/cloud-data/create-new-record) node.
## Overview
We will go through the following steps in this guide:
- Create a **Record** in the database
- Retrieving the **Id** of the newly created **Record**
- Setting initial values of the **Record**
Before starting this guide, make sure you have Cloud Services enabled and have at least one **Class** in the database. You can learn how to do this in [this](/docs/guides/cloud-data/creating-a-backend) and [this](/docs/guides/cloud-data/creating-a-class) guide.
## Create a Record using the Create New Record Node
If you tried out the **Dashboard** you could see how you could create **Records** from there. Now we will learn how to create **Records** from within an app.
Start a new Noodl Project in your workspace. You can use any template, for example the `Hello World` template.
Again, make sure you have **Cloud Services** enabled and an active **Cloud Service** set up with at least one **Class**. When opening your `Cloud Services` sidebar it should look something like the image below, with a `Used in editor` cloud service selected.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/creating-new-database-records/cloud-service-active.png)
</div>
Now open the Node Picker by right clicking in the node graph editor panel. Create a **Create New Record** node.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/creating-new-database-records/node-picker-1.png)
![](/docs/guides/cloud-data/creating-new-database-records/create-new-record-1.png)
</div>
### The Create New Record Node
As it name states, this node is used to create and insert new **Records** in a **Class** in the Database. First we need to set up which **Class** it should insert **Records** into. Click the node and select one of you **Classes** that you set up in your Backend. In this example, we select the **Class** **Task**.
<div className="ndl-image-with-background">
![](/docs/guides/cloud-data/creating-new-database-records/create-new-record-2.png)
</div>
### Initial Values
As you can see, when selecting a **Class** for your **Create New Records** node you immedieatly get new Properties on your node, namely the **Columns** you added to your **Class** when creating it. The `Task` class created in the previous guides have the `task` and the `isComplete` property.
You can add or remove **Columns** at any time in the **Dashboard** and all nodes that references to that **Class** will be updated accordingly. If you remove a **Column** that's used by your nodes, you will get warnings in Noodl.
As you probably already have figured out, by setting these properties on the node, you can control the initial values of the **Record** when creating it. So let's fill out the properties with some values, for example as below.
<div className="ndl-image-with-background">
![](/docs/guides/cloud-data/creating-new-database-records/create-new-record-3.png)
</div>
### Creating The Record
Actually creating the **Record** is easy. You need to trigger the **Do** input signal on the **Create New Record** node. So lets add a [Button](/nodes/ui-controls/button) for that purpose. Add it somewhere on your screen. In this example we add it after the **Text** node and center it and change its label.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/creating-new-database-records/app1.png)
</div>
Now connect the **Click** output signal from the **Button** to the **Do** signal of the **Create New Record** by dragging from the **Button** to the **Create New Record** node.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/creating-new-database-records/connecting-1.png)
</div>
When the two nodes are connected you are ready to try your app. Click the button in the app a couple of times. You should see the **Clicked** to **Do** connection light up. If everything works as expected, a new **Record** should be created in the database each time you click. You can double check it by opening the **Dashboard** and look in your **Class**. Note: You may have to click the **Refresh** button in the **Dashboard** to see the items.
<div className="ndl-image-with-background xl">
![](/docs/guides/cloud-data/creating-new-database-records/create-record.gif)
![](/docs/guides/cloud-data/creating-new-database-records/dashboard-1.png)
</div>
## Retrieving the id of the newly created Record
As you can see, the **Create New Record** node is kind of a **Record** creating factory. Each time **Do** is triggered a new **Record** is created. So how do you keep track of them?
The node has an output **Id**, which will be the identifyer for the **Record** just created. As a side note, assuming the creation went well, the **Success** output signal is triggered as well when the **Record** has been created. If the creation failed, for example if one of the properties of the **Record** is required and wasn't provided (see the [this](/docs/guides/cloud-data/creating-a-class/) guide), the **Failure** signal is triggered instead.
Lets connect the output **Id** of the **Create New Record** node to a **String** node to take a better look at it.
The **Id** is a special property of the **Record**. You will first notice that the **Id** of the newly created **Record** matches the **objectId** in the **Dashboard**.
<div className="ndl-image-with-background xl">
![](/docs/guides/cloud-data/creating-new-database-records/inspect-id.png)
![](/docs/guides/cloud-data/creating-new-database-records/inspect-2.png)
</div>
The **Id** is used to refer to this specific **Record**. For example, if you want to change a property of a specific **Record** you use a [Set Record Properties](/nodes/data/cloud-data/set-record-properties) node and make sure it's **Id** is referring to the correct **Record**. Same goes for the [Record](/nodes/data/cloud-data/record) node or the [Delete Record](/nodes/data/cloud-data/delete-record). So keeping track of you **Ids** is important.
## Setting initial values of a Record
Now lets add some UI so each new Task **Record** can have a different task text, and can have `isDone` set to `true` or `false`. Add a [Text Input](/nodes/ui-controls/text-input) and a [Checkbox](/nodes/ui-controls/checkbox/) and connect them to the `Create New Record` node. As you can see, the two properties coming from the **Columns** of the **Class** are available as inputs on the **Create New Record** node.
<div className="ndl-image-with-background xl">
![](/docs/guides/cloud-data/creating-new-database-records/initial-props.png)
</div>
Try out your app, write some random task descriptions and check / uncheck. See that it works correctly by looking at the data in your **Dashboard**.

View File

@@ -0,0 +1,171 @@
---
title: Filtering Database Queries
hide_title: true
---
# Filtering Database Queries
## What you will learn in this guide
In this guide you will learn how to let your database make a filtered query of your **Records**. This is a very common task in apps. For example if you want to see all comments related only to one specific post, or all messages that are unread. This is achieved by querying the database and ask it to filter out only the selected results.
In Noodl you use the [Query Records](/nodes/data/cloud-data/query-records) node to make a filtered query.
## Overview
We will go through the following steps in this guide
- Query the Database for **Records** with a property equal to a specified value
- Make a dynamic filter, i.e. where the Qurey filter can change dynamically
To get most out of this guide, it's best that you are already familiar with how to set up a cloud backend, create **Classes** and **Records** and make basic queries. You can quickly learn that by going through the following guides:
- [Creating a Backend](/docs/guides/cloud-data/creating-a-backend)
- [Creating a Class](/docs/guides/cloud-data/creating-a-class)
- [Creating Records](/docs/guides/cloud-data/creating-new-database-records)
- [Query Records](/docs/guides/cloud-data/quering-records-from-database)
- [Update Records](/docs/guides/cloud-data/updating-records)
## Filtering Records in the Cloud vs Locally
This guide is focusing in on filtering Queries in the Cloud Database. This means that **Records** and filtered before they are sent to your app over the network. This is what the [Query Records](/nodes/data/cloud-data/query-records) node does.
There is also another node, [Filter Records](/nodes/data/cloud-data/filter-records), that filters data _that is already in the app_, i.e. it filters locally.
Both of these have their advantages and disadvantages and in a good app you often mix them.
Filtering in a Query in the Database (using **Query Records**) have the following advantages
- You only send the filtered out **Records** over the network. This is incredibly important if you are working with large data sets. If you have thousands of products in a database, you only want to send the products that the user is searching for or your app will be slow.
- You can make use of optimized indexes in the Database if you for example are sorting or filtering out only certain objects. Again, if you work with large data sets with thousands or millions of **Records** this is key to make your app fast.
Filtering a Query locally (using **Filter Records**) have these main advantages
- Once the **Records** are in the app, you don't need to send **Records** over the network which makes your app much faster.
- If you have many users of your app your Backend and Database may be congested. By avoiding Querying the Cloud Database too often, for example by handling data locally, you put less stress on it.
Often, the most optimal solution is to combine the two methods. Make a Filtered Query towards the database that filters down the amount of **Records** to be sent to the app to a reasonable number, then use **Filter Records** for additional filtering and sorting locally.
In this guide, we will specifically look at filtering using the **Query Records** node. The **Filter Records** node works in a very similar fashion but only works on **Arrays** of **Records** that are already in the App, typically coming from a **Query Records** node.
## Using the Query Records node for filtering
This guide assumes that you already have a Backend up and running, with at least one Class containing a number of **Records**. You can follow the previous "Working With Cloud Data" guides if you need help with that. As an example we will use a simple Task app created in the previous guides. It has one **Class** called `Task`. It has two properties, `task` which is a description of the task, and `isDone` a boolean that keeps track of if the task is completed or not.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/filtering-database-queries/checkbox-anim.gif)
</div>
The App consists of a main screen as below:
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/filtering-database-queries/orig-app.png)
</div>
Each todo **Record** is represented by a list item constructed as below:
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/filtering-database-queries/list-item-2.png)
</div>
Now we want to add a filter to only see the uncompleted tasks. Click on the **Query Records** node in the main screen. Then click the `Add Filter Rule` button.
<div className="ndl-image-with-background">
![](/docs/guides/cloud-data/filtering-database-queries/add-filter-rule-1.png)
</div>
A new popup will appear where you can construct your filter. Feel free to play around a little with it.
<div className="ndl-image-with-background">
![](/docs/guides/cloud-data/filtering-database-queries/add-filter-rule-2.png)
</div>
It basically has three parts:
`<property> <operator> <value or input>`
The `<property>` is a property of your **Record**, for example `isDone` in our Task example.
The `<operator>` is a logical operator for the condition. There are a number of different operators and not all operators are available for all types of properties.
For the case of `isDone` - a **boolean** there are for operators available: `equal to`, `not equal to`, `exists` and `not exists`. While the `equal to` / `not equal to` are pretty self explanatory, the `exists` / `not exists` operators work in the following way: They check whether there is a value set at all for the property, or if it's undefined.
Finally the `<value or input>` is the value that the operator should be applied to. The `<input>` option we will look at later, so let's use `<value>` for now.
In our case we want to filter out only the tasks that are not yet completed, i.e with `isDone = false`. So our filter will be:
`<isDone> <equal to> <false>`
Let's select that. You can see that the somewhat cryptic format of the filter is spelled out in natural language below the filter.
<div className="ndl-image-with-background">
![](/docs/guides/cloud-data/filtering-database-queries/add-filter-rule-3.png)
</div>
You should already now see the list in your app changing to only show tasks that are uncompleted (if you have any). If you check the tasks they will start disappearing one by one as they are being filtered out. If you want them back, you will have to go into the **Dashboard** and change the `isDone` value to false again, and refresh your app.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/filtering-database-queries/completing-tasks.gif)
</div>
## Dynamic filtering
The current state of the app is obviously flawed - when you finish all your tasks you see nothing. We need to be able to switch views between the completed and the uncompleted tasks.
Lets add a [Radio Button Group](/nodes/ui-controls/radio-button-group) with two [Radio Buttons](/nodes/ui-controls/radio-button). With this, we can control wether we want to show the uncomplete tasks or the completed tasks.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/filtering-database-queries/radiobutton-1.png)
</div>
<div className="ndl-image-with-background">
![](/docs/guides/cloud-data/filtering-database-queries/radiobutton-2.png)
</div>
Make sure the label for the buttons are set correctly ("Show Uncompleted"/"Show Completed") and that their value is set to "Uncompleted"/"Completed" respectively. Also, the **Value** of the **Radio Button Group** should be "Uncompleted". That will be the default state. We will use the **Value** output of the **Radio Button Group** to control the filter settings of the **Query Records**.
Now lets update the **Query Records** node so we can control its filter using inputs. Click the **Query Records** node and change the last part of the filter to not take a value, but an **input**.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/filtering-database-queries/add-filter-rule-4.png)
</div>
Name the input "isDoneFilter". Now the **Query Records** have a new input that we can use! If the input is set to `true` we will filter out all completed tasks (`isDone = true`) and vice versa for `false`.
Finally we need to convert the two Radio Button values "Uncompleted" and "Completed" to `true` or `false`. We do that by creating an [Expression](/nodes/math/expression) node and setting the expression to
`filterState === "Completed"`
The **Expression** node will output `true` if the input is "Completed", otherwise `false`. Finally connect the output of the **Expression** to the **Query Records** and - voila! - our filtering will change when clicking the radio buttons.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/filtering-database-queries/radiobutton-3.png)
</div>
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/filtering-database-queries/radiobutton-ui.gif)
</div>

View File

@@ -0,0 +1,109 @@
# Importing and exporting data with CSV
You can import and export data to/from your cloud service in the CSV (Comma Separated Values) format. This is done in the cloud services dashboard.
To export, browse the data for a specific record class and then you find the export commands in the toolbar at the top.
<div className="ndl-image-with-background">
![](/docs/guides/cloud-data/import-export-csv/export-csv.png)
</div>
You can either export all records in a class (max 10K) or only the selected records. Select an option and then save the exported CSV.
To import a CSV you must also browse to the record class that you want to import into. Then you will find the import command in the `Edit` menu at the very bottom.
<div className="ndl-image-with-background">
![](/docs/guides/cloud-data/import-export-csv/import-csv.png)
</div>
Click and then pick the CSV file on your computer that you want to use for import. The CSV file must follow a certain format for the import to work well.
### String
The input will be assigned directly as a string.
### Boolean
When the column data type is a boolean, there are a few different formats that are possible:
```js
"True" // == true
"true" // == true
"1" // == true
1 // == true
"FalsE" // == false
"false" // == false
"0" // == false
0 // == false
```
### Number
When the column data type is a number, it will convert the input to a number and assign if the value is not invalid or NaN.
### Date
Everything that is available via `new Date(...)` will be possible to import.
For example:
```json
"Thu Apr 13 2023 10:07:29 GMT+0200 (Central European Summer Time)"
"2023-04-13T08:02:46.447Z"
"Thu, 13 Apr 2023 08:06:11 GMT"
```
### Object
You can import an object type property by specifying it as JSON:
```json
{
"some_property":10
}
```
### Array
Properties of array types can also be provided as JSON.
```json
[1,2,3]
```
### GeoPoint
A propety of type GeoPoint can be imported either as a string with latitude and longitude:
```json
"30,30"
```
Or as an object with lat/long as properties:
```json
{"latitude": 30, "longitude": 30}
```
### Pointer
A point is simply a string with the `Id` of the target record.
### Relation
This is currently not supported.
### File
```json
{
"url": "path-to-file",
"name: "filename.png"
}
```

View File

@@ -0,0 +1,13 @@
---
title: Working with Cloud Data in Noodl
hide_title: true
---
import ReactPlayer from 'react-player'
# Working with Cloud Data in Noodl
Almost all real Apps needs a database. Noodl provides a professional grade database as part of every project.
<ReactPlayer playing autoplay muted loop url='overview/db3.mp4' />
### [Learn about Cloud Data in Noodl](/docs/guides/cloud-data/creating-a-backend)

View File

@@ -0,0 +1,170 @@
---
title: Querying records From Database
hide_title: true
---
import CopyToClipboardButton from '../../../src/components/copytoclipboardbutton';
# Querying records from database
## What you will learn in this guide
In this guide you will learn how to use the [Query Records](/nodes/data/cloud-data/query-records) node to create powerful database queries to retrieve **Records** from a database. You will also learn how to use the [Repeater](/nodes/ui-controls/repeater) node in combination with a [Record](/nodes/data/cloud-data/record) node to visualize the results of a query.
## Overview
We will go through the following steps in this guide
- Create a simple query
- List results as list items using a **Repeater** node
- Connecting data properties to visual nodes
To get most out of this guide, it's best that you are already familiar with how to set up a cloud backend, create **Classes** and **Records**. You can quickly learn that by going through the following guides:
- [Creating a Backend](/docs/guides/cloud-data/creating-a-backend)
- [Creating a Class](/docs/guides/cloud-data/creating-a-class)
- [Creating Records](/docs/guides/cloud-data/creating-new-database-records)
## What is a "Query"?
In the database world a Query is how you ask a database for a specific subset of records based on some conditions. In the case of Noodl, you ask your **Cloud Service** for all **Records** in a **Class** that fullfills one or more conditions. An example of a query, in words, would be "Give me all **Records** in the **Class** `Task` where the property `isDone` is false".
## Making a Query
First make sure you have started a project with an active Backend with some data available in one or more **Classes**. Following the previous cloud data guides, we will use a **Class** called `Task`, with a bunch of items with the properties `task` - a description of a task, and `isDone` - a boolean value that is either `true` (the task ha been completed) or `false` (the task is not completed yet).
Lets start with an empty project. You can for example use the "Hello World" template and remove the text node. Add a [Repeater](/nodes/ui-controls/repeater/) node as a child to the main **Group**. We will need the **Repeater** later to visualize the results of our query.
Then create a [Query Records](/nodes/data/cloud-data/query-records) node.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/quering-records-from-database/query-1.png)
</div>
First we need to select which **Class** this **Query Records** node should be applied to. You do that by clicking the node and select a **Class** from the Class dropdown. You should expect to see all **Classes** you created in this dropdown. If you for some reason don't see them, you probably havent connected your project to the right cloud service.
<div className="ndl-image-with-background">
![](/docs/guides/cloud-data/quering-records-from-database/query-2.png)
</div>
Leave the other settings for now. Since we don't add any conditions ("filters" as they are called in Noodl) this query will return all **Records** in the `Task` Class. Or actually not always all, since Noodl will have a default limit on 100 **Records** for a Query, to avoid flooding the network if the **Class** contains a large amount of items. You can change the limit, by checking the `Use Limit` checkbox, but we will not touch that right now.
To get a first look at we get back from the Query, create an [Array](/nodes/data/array/array-node) node to store the results in. Then connect **Items** from the **Query Records** node to the **Items** input on the **Array**. You should immediately see the result of the query if you hover over the connection between the two nodes to see the debug info.
<div className="ndl-image-with-background xl">
![](/docs/guides/cloud-data/quering-records-from-database/query-running.png)
</div>
Noodl automatically runs **Query Records** as soon as they are created _unless_ the input signal **Do** is connected. Since queries and the result of queries are sent over network its sometimes important to control exactly when the query should be performed. In those cases connecting the **Do** signal to control when the query is performed is important. However, in this simple example we don't care about that so leaving it unconnected is fine.
## Visualising the query results using a Repeater node
To visualize the results we need to do a little bit of Noodling. We need to create a simple list item that can represent each **Record**.
Create a new visual component by clicking the "+" icon under components and then selecting `Visual Component`. Give the new component a good name, we will call our item "Task Item" as it will represent one task.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/quering-records-from-database/new-component.png)
</div>
In the visual component add two nodes under the existing **Group** node, one [Checkbox](/nodes/ui-controls/checkbox) and one [Text](/nodes/basic-elements/text) node. The **Checkbox** will represent the `isDone` property, while the **Text** node holds the description of the task. Also clean up the layout by setting the **layout** of the **Group** to **Horizontal** and add som padding and margins. Also the label of the **Checkbox** was removed. (You can copy the nodes using the button on the image below and paste them into your project if you want to.)
<div className="ndl-image-with-background xl">
![](/docs/guides/cloud-data/quering-records-from-database/task-item.png)
<CopyToClipboardButton
json={{"nodes":[{"id":"d4117337-b6cf-64cc-e2dd-70de4cfb10e6","type":"Group","x":0,"y":0,"parameters":{"flexDirection":"row","sizeMode":"contentHeight","paddingLeft":{"value":5,"unit":"px"},"paddingTop":{"value":2,"unit":"px"},"paddingBottom":{"value":2,"unit":"px"},"paddingRight":{"value":5,"unit":"px"}},"ports":[],"children":[{"id":"e5bdf35a-988f-9c6b-981e-0275f1884912","type":"net.noodl.controls.checkbox","x":20,"y":46,"parameters":{"useLabel":false,"alignY":"center"},"ports":[],"children":[]},{"id":"5fbfaf9d-919f-699f-1e1a-fcbdd20c7631","type":"Text","x":20,"y":92,"parameters":{"marginLeft":{"value":10,"unit":"px"},"sizeMode":"contentSize"},"ports":[],"children":[]}]}],"connections":[],"comments":[]}}
/>
</div>
The looks don't matter right now and if you work with different kind of data your list item will look a little different.
Next we go back to our main App and set the **Template** of the **Repeater** node to use our newly created Task Item.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/quering-records-from-database/repeater-template.png)
</div>
Finally, we delete the **Array** node we created earlier and feed the result of the query results directly into the **Repeater** node by connecting **Items** in the **Query Records** node to the **Items** input in the **Repeater**.
<div className="ndl-image-with-background xl">
![](/docs/guides/cloud-data/quering-records-from-database/query-to-repeater.png)
</div>
After the connection is done you should see that your list now contains a bunch of items, in fact, it should contain as many items as your **Class** has.
The **Repeater** node has created one instance of the list item per **Record**.
<div className="ndl-image-with-background">
![](/docs/guides/cloud-data/quering-records-from-database/items-1.png)
</div>
The only problem is that the items does not show the content of the **Record**. To fix that we need to understand how the **Repeater** node deals with an **Array** of **Records**.
### Repeater and Records
To get the items to show the right data, we need to get hold of the **Record** holding the right data. We do this by using the [Record](/nodes/data/cloud-data/record) node. Add a **Record** node to the previously created list item. Click the node and make sure its **Class** is set to the class you want to display, in this guide we will point it to the `Task` Class.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/quering-records-from-database/record-1.png)
</div>
Now the **Id** of the **Record** comes into play - we need to set it to the **Id** corresponding to the **Record** that the list item represent. It will obviously be different for each list item. Luckily, the **Repeater** node solves this. It will assign the right **Id** to the right list item. See image below.
<div className="ndl-image-with-background xl">
![](/docs/guides/cloud-data/quering-records-from-database/records-database-illustration.png)
</div>
The only thing we need to do is to tell the **Record** node to pick up its **Id** from the right place. Click the **Record** node again and change the **Id Source** to `From repeater`.
<div className="ndl-image-with-background">
![](/docs/guides/cloud-data/quering-records-from-database/id-source.png)
</div>
Now if you hover on the **Repeater** you should see that its filled with data for one of the list items.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/quering-records-from-database/record-2.png)
</div>
### Connecting the Record properties
Finally, lets connect the data of the record - its properties - to our **Text** node and **Checkbox**.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/quering-records-from-database/record-3.png)
</div>
You should now be able to see your **Records** in your app.
<div className="ndl-image-with-background">
![](/docs/guides/cloud-data/quering-records-from-database/items-2.png)
</div>

View File

@@ -0,0 +1,129 @@
---
title: Records Relationships
hide_title: true
---
# Record Relationships
## What you will learn in this guide
In this guide we will look into relationships between different **Records** in the database. This could for example be a _pointer_ stored in a **Record** that points to another **Record**. It could also be a "Many to Many" relationship where an **Record** can have a list of _pointers_ to other **Records**.
This is very useful when you deal with _relational data_, for example if you have a Post **Class** in your database, and you want to keep track of all the **Users** (another **Class**) that liked that post, a **Post** record can store relations to those Users in a property.
## Overview
We will first look at **Pointers**, i.e. a _One-to-many_ relationship. Then we will look at **Relations**, i.e. _Many-to-many relationshipts_.
It's recommended that you have some experience working with Backends, Databases and **Records** to get most out of this guide, so if you haven't already, going through the following guides before is recommended.
- [Creating a Backend](/docs/guides/cloud-data/creating-a-backend)
- [Creating a Class](/docs/guides/cloud-data/creating-a-class)
- [Creating Records](/docs/guides/cloud-data/creating-new-database-records)
## Relationships between Records
If we imagine an App where we have a couple of different **Classes**, say a _Post_ Class that contains blog posts and a _Comment_ Class with comments on these post. The **Records** in these classes need to be related and we need to be able to query these relations.
## Pointers - One-to-many relationships
The most simple relationship is a **Pointer**. This type of relationship is often referred to as a _One-to-many_ relationship. For example, a blog _Post_ will have many *Comment*s, but each _Comment_ only belong to one _Post_. To create this kind of relationship we use a property of a special kind called a **Pointer**.
A **Pointer** property can reference another **Record** of a certain Class via it's _Id_. In this case we want to reference the _Post_ that is the owner of a _Comment_. So in the _Comment_ class we create a property, let's call it `Owner`, and give it a _Pointer_ type and specify that it should point to _Post_ records.
?> This is called a _backward_ relationship, i.e. the _Comment_ points back to the _Post_. If you want to find all _Comments_ for _Post_ you will simply look for all _Comments_ pointing back to the _Post_ you are interested in.
<div className="ndl-image-with-background">
![](/docs/guides/cloud-data/record-relations/create-pointer.png)
</div>
Now to set the pointer you can pass in the **id** of a **Post** Record. You could for example do this when you create a new _Comment_ **Record** . It's important the the **Record** you point to is of the right type. In this case a _Post_.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/record-relations/insert-pointer.png)
</div>
Later, if you want to retrieve all the _Comments_ for a _Post_ you simply use a **Query Records** node and ask for all **Comments** where the **Owner** property points to the specific comment.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/record-relations/query-pointer-1.png)
</div>
The specific **id** we are looking for, we provide through an input.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/record-relations/query-pointer-2.png)
</div>
You can inspect your relationships in the data browser, if you go ahead and open the _Dashboard_ for the cloud services and find the _Comment_ Class. There you can see the record _Id_ that the pointer currently points to, and you can click it to jump to that particular record.
<div className="ndl-image-with-background">
![](/docs/guides/cloud-data/record-relations/comments-owner.png)
</div>
## Relation - Many-to-many relationships
Let's say that we introduce a new **Class** called _Group_, and a _Post_ can be part of many different *Group*s. In this case we cannot use the backwards pointing mechanism from the previous example. One single pointer from the _Post_ to the _Group_ would not work, since a _Post_ can be part of many _Groups_. Instead we need to use a concept called **Relation**. You need to start by creating a new property of the _Group_ **Record** that have the type _Relation_ and like pointers you need to specify the _Type_ and give it a name.
?> So in this case it becomes a _forward_ reference, the _Group_ has the relation property.
<div className="ndl-image-with-background">
![](/docs/guides/cloud-data/record-relations/create-relation.png)
</div>
It can be a bit tricky in the beginning to get the hang of relations. One way to look at it is this: In this example, A _Group_ have a list of pointers to all its _Posts_ that belongs to it. So a specific _Group_ can easily find its _Posts_ by following these pointers. The inverse question, a _Post_ who wants to know which _Groups_ it belongs to (it can be more than one!) can query for all _Groups_ that have a pointer in its list that's pointing at them.
When you have a _Relation_ property on a **Record** you need to use the nodes [Add Record Relation](/nodes/data/cloud-data/add-record-relation) and [Remove Record Relation](/nodes/data/cloud-data/remove-record-relation) to manage them. In these nodes you need to provide the **id** of the **Record** that has the relation property (Group in our case) and the **id** of the **Record** you want to add or remove to the relationship.
<div className="ndl-image-with-background">
![](/docs/guides/cloud-data/record-relations/record-relation-1.png)
</div>
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/record-relations/record-relation-2.png)
</div>
In the same manner as with _Pointers_ you can go to the _Dashboard_ of the cloud services and find the relations of your models in the table. You can click _View relation_ to get a table of the relations for this particular model.
<div className="ndl-image-with-background">
![](/docs/guides/cloud-data/record-relations/view-relation.png)
</div>
Finally you need to be able to query the relations. You have two cases:
1. Either you want to find all _Post_ that are related to a _Group_. The you should create a **Query Records** of the class _Post_ (you want _Posts_ back from the query). You can then set up the filter according to the image below
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/record-relations/query-relation-1.png)
</div>
Note that you have to specify the name of the relation property in the class having the property (_Group_ in this case) as well.
2. If you want to make the inverse query, that is you want to ask for all _Groups_ that relates to a post, you create a **Query Records** node with the class _Group_ (you want _Groups_ back from the query). have a _Post_ **Record** (you have the _Id_ of a _Post_ **Record**) and you want to find all *Group*s that it belongs to you would use this javascript query in a **Query Records** that is set to the **Group** class.
```javascript
where({
posts: { pointsTo: Inputs.PostId },
})
```
As you can see above you must also make sure that you use the correct relation field, in this case _posts_ on the _Group_ collection.

View File

@@ -0,0 +1,102 @@
---
title: Updating Records
hide_title: true
---
# Updating Records in the Database
## What you will learn in this guide
In this guide you will learn how to use the [Set Record Properties](/nodes/data/cloud-data/set-record-properties) node to update data in the Database.
## Overview
We will go through the following steps in this guide
- Update previously queried **Records**
To get most out of this guide, it's best that you are already familiar with how to set up a cloud backend, create **Classes** and **Records** and query them. You can quickly learn that by going through the following guides:
- [Creating a Backend](/docs/guides/cloud-data/creating-a-backend)
- [Creating a Class](/docs/guides/cloud-data/creating-a-class)
- [Creating Records](/docs/guides/cloud-data/creating-new-database-records)
- [Query Records](/docs/guides/cloud-data/quering-records-from-database)
## Updating Records in the database
It's simple to update **Records** in the database using the [Set Record Properties](/nodes/data/cloud-data/set-record-properties) node. You basically make sure the **Id** is set to the right **Record**, set the properties to what you want them to be and signal the **Do** input.
To try it out, make sure you have a cloud service active for your project. Set up a **Class** in the Database with some **Records** in. Finally Query some items from the **Database**. If you follow the previous "Working With Cloud Data" guides you can use the simple Task list created there. It looks something like this:
<div className="ndl-image-with-background">
![](/docs/guides/cloud-data/updating-records/items-2.png)
</div>
The app has two components, the main component called "App" and a List Item called "Task Item".
The main component that looks like this:
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/updating-records/orig-app.png)
</div>
And the list item like this
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/updating-records/record-3.png)
</div>
A clear shortcoming of this small app is that when you complete a task and check its checkbox the database wont actually update. The `isDone` property will not change.
You can double check that by clicking a few items and reload the app. The changes are only visual, the underlying data is not changed.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/updating-records/checkbox-anim.gif)
</div>
### The Set Record Properties node
To update a **Record** you use the [Set Record Properties](/nodes/data/cloud-data/set-record-properties) node.
Add the node to your List Item. Click it, to edit its properties, and make sure the correct **Class** is selected.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/updating-records/list-item-1.png)
</div>
<div className="ndl-image-with-background">
![](/docs/guides/cloud-data/updating-records/set-record-prop-1.png)
</div>
Also note the option `Store to`. You can chose to store changes either locally and in the cloud, or only locally. Let it be set to `Cloud and locally` as we our changes to be stored directly in the database.
Sometimes it makes sense to only store the changes locally at first. For example, if you have a form with multiple fields and a "Save" button, it might make sense to first store only locally and when the user presses "Save" to store all changes at once.
Now we need to make sure the **Id** of the **Set Record Properties** are set correctly to the **Id** that the **Repeater** provides.
<div className="ndl-image-with-background">
![](/docs/guides/cloud-data/updating-records/set-record-prop-2.png)
</div>
Now the only two things left to do is to connect the **Checkbox** to the `isDone` property and trigger the **Do** signal of the **Set Record Properties**. We want to save whenever the state of the **Checkbox** is updated, so lets connect the **Changed** signal coming out of the **Checkbox** to **Do**.
<div className="ndl-image-with-background l">
![](/docs/guides/cloud-data/updating-records/list-item-2.png)
</div>
We're done! Click on your different tasks and double check that they are correctly saved by bringing up your **Dashboard** inspect the `isDone` properties. Don't forget to press `Refresh` in the **Dashboard** to update the view.