Parse Cloud Code: Modify Object before Retrieval - parse-platform

Let's say I have a Users class and a Posts class, and each Post object has a User pointer. I also have a Comment class, and each Comment has a User pointer. Whenever I fetch a User, I want to fetch all the Posts and Comments that user has made in one network query. Compounding sub-queries won't work, since I have multiple data types. Ideally, I would like to have the Posts and Comments be properties of the retrieved User object.
Is there a way, in Cloud Code, to intercept object requests and modify them to have the appropriate properties before sending to the client?

You can't modify an object on retrieval, but you can write your own Cloud Function. In your Cloud Function you could take the ID of a user as a parameter, then create a composite object by combining the output of your 3 queries into one result.
You'll need to query:
User object
Posts for that user
Comments for that user
You could get the promise for each of those queries (find() etc return a promise object) and use Parse.Promise.when(userQueryPromise, postQueryPromise commentQueryPromise) to build your composite object and return it.
var _ = require('underscore');
Parse.Cloud.define('getUserWithPostsAndComments', function(request, response) {
var userId = request.params.userId;
var userPointer = new Parse.User();
userPointer.id = userId;
var userQuery = new Parse.Query(Parse.User);
var postQuery = new Parse.Query('Post');
postQuery.equalTo('user', userPointer);
var commentQuery = new Parse.Query('Comment');
commentQuery.equalTo('user', userPointer);
Parse.Promise.when(userQuery.get(userId), postQuery.find(), commentQuery.find())
.then(function(user, posts, comments) {
var composite = {
// User properties you want
name: user.get('username'),
email: user.get('email')
};
// Post properties you want
composite.posts = _.map(posts, function(post) {
return {
id: post.id,
title: post.get('title')
};
});
// Comment properties you want
composite.comments = _.map(comments, function(comment) {
return {
id: comment.id,
body: comment.get('bodyText')
};
});
// return the composite object
response.success(composite);
}, function(error) {
response.error(error);
});
});
Alternatively the above then block could just return the raw results, e.g.:
.then(function(user, posts, comments) {
return {
user: user,
posts: posts,
comments: comments
};
}, function(error) {
// etc...

Related

async update(params, data, { files } = {}) does not work

my project was created with Strapi 3.0.0-beta.18.6.
But in the service of the content type "Orders" the (new) "update" method does not work, only the (old) "edit" works.
Can someone give me a tip?
// ---------------- "update" does not work :( ------------------
async update(params, data, { files } = {}) {
const query = strapi.query('order');
const entry = await query.update(params, data);
if (files) {
// automatically uploads the files based on the entry and the model
await this.uploadFiles(entry, files, { model: strapi.models.order });
return this.findOne({ id: entry.id });
}
return entry;
},
by the way, query.update(params, data); cannot be executed, the process is canceled, but there is no error message.
// ---------------- old "edit" works ------------------
async edit (params, values) {
// Extract values related to relational data.
const relations = _.pick(values, Order.associations.map(ast => ast.alias));
const data = _.omit(values, Order.associations.map(ast => ast.alias));
// Create entry with no-relational data.
const entry = Order.forge(params).save(data);
// Create relational data and return the entry.
return Order.updateRelations(Object.assign(params, { values: relations }));
},
Thanks in advance!
Strapi generated controllers are based on the shadow core controller function.
If you want to customize the default function you can refer to this documentation : https://strapi.io/documentation/3.0.0-beta.x/concepts/controllers.html#core-controllers
I just tried it and it works fine.

Apollo and AwsAppsync repeating mutation in callback

I have an awsAppSync client that is set up as follows:
that._getClient = function() {
return client = new AWSAppSyncClient({
url: appSyncUrl,
region: AWS.config.region,
auth: {
type: AUTH_TYPE.AWS_IAM,
credentials: AWS.config.credentials
}
});
}
And a mutate function that is called like this:
that.mutate = function(mutation, variables) {
let client = that._getClient();
return client.mutate({ mutation: mutation, fetchPolicy: 'no-cache', variables: variables })
.then(function (result){
return result;
});
}
I need to make subsequent queries to create different records that depend on one another, so I'm returning the Id of the newly created record to use in the callback of the previous query.
The problem is, that in every callback where the mutate function is called, the mutation that caused this callback gets executed again. For example, I do:
appSync.mutate(mutation, requestParams)
.then(function (response) {
let id = response.id
requestParams = {//new stuff}
return appSync.mutate(mutation, requestParams)
})
.then(//and so forth)
Now, I've seen some posts on here that say that it might be something to do with the optimistic response, and so on, but I actually get two new records in my database. I also considered the cache doing something trippy, but As you can see from the code, I (think) disabled it for the mutation.
Please help.

parse cloud code query in for loop

I have a table called friends with fields
userid and friendid.
I want to query the database to find a user's friends. This is working fine by using the following code:
Parse.Cloud.define("searchfriend", function(request, response) {
var query = new Parse.Query("friends");
query.equalTo("player", request.params.myid);
query.find({
success: function(results) {
var listfreundids = [];
for (var i = 0; i < results.length; ++i) {
listfreundids[i] = results[i].get("friend");;
}
response.success(listfreundids);
},
error: function() {
response.error("error");
}
});
});
Now I have the problem to find the username matching the friendid because i cannot use a 2nd query within the for loop to query the user database...
Using promises you can split this up into several separate parts. Promises are really awesome to use and really easy to create your own promises too.
What I would do is split this up into a query that finds the friend ids and then a query that finds the friends...
Parse.Cloud.define("searchfriend", function(request, response) {
getFriendIDs(request.params.myid).then(function(friendIDs) {
return getFriendUserNames(friendIDs);
}).then(function(friends) {
response.success(friends);
}), function(error) {
response.error(error);
});
});
// function to get the IDs of friends
function getFriendIDs(myID) {
var promise = new Parse.Promise();
var query = new Parse.Query("friends");
query.equalTo("player", myID);
query.find().then(function(friendIDs) {
promise.resolve(friendIDs);
}, function(error) {
promise.reject(error);
});
return promise;
}
// function to get the friends from a list of IDs
function getFriendUserNames(friendIDs) {
var promise = new Parse.Promise();
var query = new Parse.Query("_User");
query.containedIn("id", friendIDs);
query.find().then(function(friends) {
// here I am just returning the array of friends
// but you can pull the names out if you want.
promise.resolve(friends);
}, function(error) {
promise.reject(error);
});
return promise;
}
You could always user a matches query too...
// function to get friends
function getFriends(myID) {
var promise = new Parse.Promise();
var friendQuery = new Parse.Query("friends");
friendQuery.equalTo("player", myID);
var userQuery = new Parse.Query("User");
userQuery.matchesKeyInQuery("ID", "friendID", friendQuery);
userQuery.find().then(function(friends) {
promise.resolve(friends);
}, function(error) {
promise.reject(error);
});
return promise;
}
This will perform a joined query where it gets the friend IDs first and then uses the friend ID to get the user and returns the user object.
Also, use promises. They are much easier to work with and can be pulled apart into separate working units.
Of course, I have no idea if the syntax here is correct and what the correct names should be or even what your object model looks like but hopefully this can act as a guide.
You do not have to query for each friend id that you have found (inefficient). Instead, after getting the list of friend ids, you can query the user database via sending the list of friend ids with the query.containedIn constraints. This strategy will actually decrease the number of query count.Based on retrieved result you can get friend (previously found) information. One more thing to remember, call response success after the operations are executed.Hope this helps.
Regards.

mongoose populate different database

I have two databases in my program. One for saving users and roles and one for the rest.
1) my model User has a reference to Roles. So I can populate roles by doing:
User.find({}).populate('local.roles').sort({ email: 1 }).exec(function (err, users) { ...
This works perfect and I can get a user and his roles.
2) When I try to do the same, but with models that have a connection to another database, I get the infamous error:
"MissingSchemaError: schema hasn't been registered for model ..."
This is the way I code my models when they use a different connection:
var mongoose = require('mongoose');
// to define another mongoose connection
var configScrwebDB = require('./../../config/scrwebDatabase.js');
var scrwebDBConnection = mongoose.createConnection(configScrwebDB.url);
var aseguradoSchema = mongoose.Schema({
nombre: { type: String },
abreviatura: { type: String },
rif: { type: String },
direccion: { type: String }
});
module.exports = scrwebDBConnection.model('Asegurado', aseguradoSchema);
3) this is what I do to 'populate' some field in my query (and the one that fails with above error):
var query = Riesgo.find({ cia: filtroObject.ciaSeleccionada });
query.populate('asegurado');
query.sort("codigo");
query.select("codigo fechaInicio estado moneda");
query.exec(function (err, riesgos) { ...
Of course this is in another 'js' file; and I do my 'require', etc., in order to import my models; etc.
As I said before, I can populate when models use 'default' mongoose connection.
Any ideas how I should correct this will be appreciated ... Am I missing some obvious thing here?
Thanks and bye ...
I had the same error. You could use:
var query = Riesgo.find({ cia: filtroObject.ciaSeleccionada });
query.populate('asegurado','fields to retrieve',User);// User need to be defined in the file as an variable that contents the User model defined.
query.sort("codigo");
query.select("codigo fechaInicio estado moneda");
Refer link

parse, PFQuery in cloud code how to filter columns?

I am writing a cloud code function in parse. I am running a query and I am trying to figure out how to filter columns of the object I am querying for.
So, I am querying for user objects:
var userQuery = new Parse.Query(Parse.User);
userQuery.notEqualTo("username", username);
// so here how do I tell the query not return the values found in a column called "count"?
Thank you
You need to use .select()
Example below:
Parse.Cloud.define("testFunction", function(request, response) {
var userQuery = new Parse.Query(Parse.User);
userQuery.contains("objectId","7Ijsxy1P8J");
//Here you say which columns you want, it will filter all other ones
userQuery.select("objectId", "firstName", "lastName");
userQuery.first({
success: function(result) {
response.success(result);
},
error: function(error) {
response.error("Failed with error ", error);
}
});
});
Over there I get a PFUser by its objectId but filtering only some fields. Hope it helps.

Resources