BeforeSave Cloud Function Validate

Hello! I’ve written a beforeSave trigger to make sure that when a user creates a new project, the title is unique. I first call a query to make an array of all projects titles, then try to make sure the input title doesn’t match any of them. The error is firing regardless if the name is unique or not. Any help would be appreciated! (Also any recommendations to make this more efficient are welcome as well)

Moralis.Cloud.beforeSave("Projects", async (request) => {
  const query = new Moralis.Query("Projects");
  const queryResults = await query.find({useMasterKey:true});
  const results = [];
  for (let i = 0; i < queryResults.length; ++i) {
    results.push({        
      "title": queryResults[i].attributes.title,
    });
  }  
// do any additional beforeSave logic here
},{
  fields: {
    title : {
      options: title => {
        let match = 0;
        for (let i = 0; i < results.length; ++i) {
          if(title == results[i].title){
            match++
          };
        };
        return match == 0;
      },
      error: 'You must choose a unique name for your project.'
    }
  }
});

Hi,
You can debug your code by adding lines of this type: logger.info(results);

Hi @solalch,

Here is my solution…

The Cloud function: not possible to reference the results array in the ‘options’ part…

Moralis.Cloud.beforeSave("Projects", async (request) => {
  const logger = Moralis.Cloud.getLogger();
  logger.info("beforeSave!");
  logger.info(request.object.get('title'));
  const query = new Moralis.Query("Projects");
  query.equalTo("title", request.object.get('title'));
  const queryResults = await query.find({useMasterKey:true});
  logger.info("queryResults length="+queryResults.length);
  if(queryResults.length > 0){
    throw 'You must choose an unique name for your project.';
  } 
  // do any additional beforeSave logic here
});

To be complete, here index.html file to test it:
(including logger for debugging :wink: )

<html>
  <head>
    <!-- Moralis SDK code -->
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/web3.min.js"></script>
    <script src="https://unpkg.com/moralis/dist/moralis.js"></script>
  </head>
  <body>
    <h1>Moralis</h1>

    <p><input type="text" id="projectname" />
    <button id="btn-save-projectname">Save Projectname</button>
    <span id="save-result"></span></p>

    <script>
      // connect to Moralis server
      Moralis.initialize("..fill in..");
      Moralis.serverURL = "..fill in..";

      async function saveProject() {
        const projectname = document.getElementById("projectname").value;

        const Project = Moralis.Object.extend("Projects");
        const project = new Project();

        project.save({title:projectname}).then((project) => {
          document.getElementById("save-result").innerText = 'Project successfully saved!';
        }, (err) => { 
          const error = JSON.parse(JSON.stringify(err)); /* Strange, but have to do this.. */          
          document.getElementById("save-result").innerText = `Error ${error.code}: ${error.message}`;
        });
      }

      document.getElementById("btn-save-projectname").onclick = saveProject;
    </script>
  </body>
</html>

Easily run this with ‘python -m http.server’ from the commandline in map with the index.html file and in your (local) browser: http://localhost:8000
(Optional: download + install python from here: https://www.python.org/downloads/ )

Success!

3 Likes

Thanks for helping bro

1 Like

Wow, thank you so much! I’m using react to build the app (as I learn it lol) but most def appreaciate the html example as well. And will be excited to share it with you guys as v1 is almost done! “Made with Moralis!!!”
(ps just started programming this year with IOT Academy/Codecademy)

This was a simple solution! Seeing how to use the object, as well as how to utilize the logger during a request if very helpful as well! I do spend many hours trying to figure this out before I come to you and as always appreciate the help.

:partying_face:

Great, learning by example and that’s why i let the logger lines in the code.

See also this video to see the log lines in a command/prompt (console) window (not the console of the browser :wink: )

Happy coding

1 Like

CasNWK! I’ve discovered something about this method to where I wouldn’t recommend it as a solution.

This trigger checks to make sure the name of the project is unique before saving. That’s great for preventing new projects from having the same name, however, after creating a project, this method doesn’t allow saving new information to the project. I’m implementing reviews and storing them as relations as a field under projects and just discovered this!

I’m working on being creative and finding a solution and I’ll post here when I do find one. If you beat me to it, feel free to share your recommendation. Thanks!

Reporting back! So it wasn’t as bad as I though lol. It took me a little while but this was fruitful in many ways. For the past several weeks I’ve had trouble with querying objectId, but just discovered how to properly call it. So, I add this line in the cloud function to only throw if the objectId doesn’t match for the project being saved/created! Awesome!

Here’s the code:

  if(queryResults.length > 0){
    if(queryResults[0].id != request.object.id) {
    	throw 'You must choose an unique name for your project.';
     }
  };
1 Like

Hi,
Great you found this improvement yourself!
You can combine the 2 if’s like:

if ((queryResults.length > 0) && (queryResults[0].id != request.object.id)) {
	throw 'You must choose an unique name for your project.';
};

The extra ( and ) around each condition is not realy needed, but i do that just to be clear.

2 Likes

Amazing job guys! Thank you for sharing such cool solutions :star_struck:

Thank you!

Like to do this more often: help / support here, seems to become ‘my new carreer’ :wink: .
And available to help in projects.

2 Likes