Woodshop for old agent generation
Try the new agent generation
  • What is woodshop
  • How to's
    • Smart Relationship
      • GetIdsFromRequest
    • Smart views
      • Display a calendar view
      • Create a custom tinder-like validation view
      • Create a custom moderation view
      • Create a dynamic calendar view for an event-booking use case
    • Configure environment variables
      • NodeJS/Express projects
    • Elasticsearch Integration
      • Interact with your Elasticsearch data
      • Elasticsearch service/utils
      • Another example
    • Zendesk Integration
      • Authentication, Filtering & Sorting
      • Display Zendesk tickets
      • Display Zendesk users
      • View tickets related to a user
      • Bonus: Direct link to Zendesk + change priority of a ticket
    • Dwolla integration
      • Display Dwolla customers
      • Display Dwolla funding sources
      • Display Dwolla transfers
      • Link users and Dwolla customers
      • Dwolla service
    • Make filters case insensitive
    • Use Azure Table Storage
    • Create multiple line charts
    • Create Charts with AWS Redshift
    • View soft-deleted records
    • Send Smart Action notifications to Slack
    • Authenticate a Forest Admin API against an OAuth protected API Backend
    • Translate your project into TypeScript
      • V8
        • Migrate Mongoose files
        • Migrate Sequelize files
      • v7
        • Migrate Mongoose files
        • Migrate Sequelize files
      • v6
    • Geocode an address with Algolia
    • Display/edit a nested document
    • Send an SMS with Zapier
    • Hash a password with bcrypt
    • Display a customized response
    • Search on a smart field with two joints
    • Override the count route
    • Make a field readOnly with Sequelize
    • Hubspot integration
      • Create a Hubspot company
      • Display Hubspot companies
    • Impersonate a user
    • Import data from a CSV file
    • Import data from a JSON file
    • Load smart fields using hook
    • Pre-fill a form with data from a relationship
    • Re-use a smart field logic
    • Link to record info in a smart view
    • Display data in html format
    • Upload files to AWS S3
    • Display AWS S3 files from signed URLs
    • Prevent record update
    • Display, search and update attributes from a JSON field
    • Add many existing records at the same time (hasMany-belongsTo relationship)
    • Track users’ logs with morgan
    • Search on relationship fields by default
    • Export related data as CSV
    • Run automated tests
  • Forest Admin Documentation
Powered by GitBook
On this page
  • Requirements
  • How it works
  • Directory: /models
  • Directory: /forest
  • Directory: /routes

Was this helpful?

  1. How to's

Display, search and update attributes from a JSON field

PreviousPrevent record updateNextAdd many existing records at the same time (hasMany-belongsTo relationship)

Last updated 2 years ago

Was this helpful?

This example shows you how to display information from a JSON field using smart fields.

‌ Here a user record has a field contact of the type JSONB that includes an email and a phone attribute. On the users collection, we want to implement smart fields (called email and phone) that will display the value of information contained within the JSON as separate fields and be able to update these fields.

Requirements

‌

  • An admin backend running on forest-express-sequelize

  • A PostgreSQL database including a table with a JSONB column

‌

How it works

Directory: /models

This directory contains the users.js file where the model is declared.

/models/users.js
module.exports = (sequelize, DataTypes) => {
  const { Sequelize } = sequelize;
  const Users = sequelize.define('users', {
    contact: {
      type: DataTypes.JSONB,
    },
  }, {
    tableName: 'users',
    timestamps: false,
    schema: process.env.DATABASE_SCHEMA,
  });

  Users.associate = (models) => {
  };

  return Users;
};

Directory: /forest

This directory contains the users.js file where the smart fields email and phone are implemented.

The get() method retrieves the value that will be displayed in the UI and the set() method allows to specify the logic to be followed with regards to the input value entered upon edit. Here we will handle the update at the routes level so we just pass the object as a result of the set() method.

/forest/users.js
const { collection } = require('forest-express-sequelize');

collection('users', {
  actions: [],
  fields: [
    {
      field: 'email',
      type: 'String',
      get: (object) => {
        return object.contact ? object.contact.email : null;
      },
      search: (query, search) => {
        // Add search on contact->email field of the JSONB
        const searchCondition = {
          'contact.email': { [Op.iLike]: `%${search}%` },
        };
  
        query.where[Op.and][0][Op.or].push(searchCondition);
        return query;
      },    
      set: (object, email) => {
        return object;
      },
    }, {
      field: 'phone',
      type: 'String',
      get: (object) => {
        return object.contact ? object.contact.phone : null;
      },
      set: (object, phone) => {
        return object;
      },
    },
  ],
  segments: [],
});

Directory: /routes

This directory contains the users.js file where the implementation of the PUT route for the update action is handled.

Note that a JSON field cannot be updated attribute per attribute, it needs to be updated as a whole as not to erase the values already contained in it.

/routes/users.js
const express = require('express');
const { PermissionMiddlewareCreator, RecordGetter } = require('forest-express-sequelize');
const { users } = require('../models');

const router = express.Router();
const permissionMiddlewareCreator = new PermissionMiddlewareCreator('users');
//...


// Method to update a JSON object
function updateJson(record, formAttributes, jsonField, jsonAttributes) {
  const json = record[jsonField] || {};
  jsonAttributes.forEach((attribute) => {
    json[attribute] = attribute in formAttributes ? formAttributes[attribute] : json[attribute];
  });
  return json;
}

// Update a User
router.put('/users/:recordId', permissionMiddlewareCreator.update(), (request, response, next) => {
  const recordGetter = new RecordGetter(users, request.user, request.query);
  const attr = request.body.data.attributes;
  recordGetter.get(request.params.recordId).then((record => {
    attr.contact = updateJson(record, attr, 'contact', ['email', 'phone']);
    return record.update(attr);
  }))
  .then((recordUpdated) => recordGetter.serialize(recordUpdated))
  .then((recordSerialized) => response.send(recordSerialized))
  .catch(next);
});

//...

module.exports = router;
Logo29 July, 2020 - Loom RecordingLoom