Firstly, sorry if this is already answered, but I couldn't find it.
I'm having some trouble retrieving all attributes from a Parse response.
I found this select() method on the documentation, which would do exactly what I need, pointing out which columns should be returned, but it seem to
take no effect.
The bit of code
var answersQuery = new Parse.Query("answer");
answersQuery.select(["objectId", "description", "category_id", "sale_id", "image_url"]);
answersQuery.equalTo("previous_question_id", {
__type: "Pointer",
className: "question",
objectId: questionId
});
answersQuery.find().then(function(answersData) {
if (typeof(answersData) != "undefined") {
var answers = [];
for (var i in answersData) {
answers.push({
id : answersData[i].id,
sale_id : answersData[i].get("sale_id"),
image_url : answersData[i].get("image_url"),
category_id: answersData[i].get("category_id"),
description: answersData[i].get("description")
});
}
response.success({
answers : answers
});
} else {
response.error("answers not found");
}
});
But the return I get always contains just the "id" and the "description" attributes
{"result":{"answers":[{"description":"COMPRAS","id":"x3pS8sadDS"},{"description":"CINEMA","id":"MVHwJqifzE"}]}}
If I change the "id" to something like "asdf" it will reflect in the response, so I'm sure I'm dealing iwth the same object I can see in the response.
Any ideas would be much appreciated.
Does the answers table has too many fields? Have you tried not specifying fields (I mean, to using the select statement)?
Related
First, I will show the state stored in mongodb.
As you can see, it is a structure with a list called replies in a list called comments. And inside replies there is an array called likes.
comments : [
Object1 : {
replies : [
likes : [
0 : {},
1 : {}
]
]
},
Object2 : {
replies : [
likes : [
0 : {},
1 : {}
]
]
}
]
What I want to do here is to insert/subtract a value only from the likes array inside a specific replies structure. I'm currently using Spring boot and have tried the following:
Query query = new Query();
Criteria criteria = Criteria.where("_id").is(new ObjectId(postId))
.andOperator(Criteria.where("comments")
.elemMatch(Criteria.where("_id").is(new ObjectId(commentId))
.andOperator(Criteria.where("replies")
.elemMatch(Criteria.where("_id").is(new ObjectId(replyId)))
)
)
);
query.addCriteria(criteria);
Update update = new Update();
if (state) {
// remove user id
update.pull("comments.$[].replies.$.likes", new ObjectId(userId));
} else {
// add user id
update.push("comments.$[].replies.$.likes").value(new ObjectId(userId));
}
mongoTemplate.updateFirst(query, update, MyEntity.class);
It is an operation to add or remove userId according to boolean state. As a result of the attempt, up to a specific comment is found, but userId is unconditionally entered in the first likes list of the replies list inside the comment. What I want is to get into the likes list inside a specific reply. Am I using the wrong parameter in update.push()? I would appreciate it if you could tell me how to solve it.
Not a direct answer to your question as I'm not experienced with spring's criteria builder, but here's how you would do it in mongo directly, which might help you to figure it out:
You could define arrayfilters allowing you to keep track of the corresponding indices of each comments and replies. You can then use those indices to push a new object at the exact matching indices:
db.collection.update({
_id: "<postId>"
},
{
$push: {
"comments.$[comments].replies.$[replies].likes": {
_id: "newlyInsertedLikeId"
}
}
},
{
arrayFilters: [
{
"comments._id": "<commentId>"
},
{
"replies._id": "<replyId>"
}
]
})
Here's an example on mongoplayground: https://mongoplayground.net/p/eNdDXXlyi2X
A content-type "Product" having the following fields:
string title
int qty
string description
double price
Is there an API endpoint to retrieve the structure or schema of the "Product" content-type as opposed to getting the values?
For example: On endpoint localhost:1337/products, and response can be like:
[
{
field: "title",
type: "string",
other: "col-xs-12, col-5"
},
{
field: "qty",
type: "int"
},
{
field: "description",
type: "string"
},
{
field: "price",
type: "double"
}
]
where the structure of the schema or the table is sent instead of the actual values?
If not in Strapi CMS, is this possible on other headless CMS such as Hasura and Sanity?
You need to use Models, from the link:
Link is dead -> New link
Models are a representation of the database's structure. They are split into two separate files. A JavaScript file that contains the model options (e.g: lifecycle hooks), and a JSON file that represents the data structure stored in the database.
This is exactly what you are after.
The way I GET this info is by adding a custom endpoint - check my answers here for how to do this - https://stackoverflow.com/a/63283807/5064324 & https://stackoverflow.com/a/62634233/5064324.
For handlers you can do something like:
async getProductModel(ctx) {
return strapi.models['product'].allAttributes;
}
I needed the solution for all Content Types so I made a plugin with /modelStructure/* endpoints where you can supply the model name and then pass to a handler:
//more generic wrapper
async getModel(ctx) {
const { model } = ctx.params;
let data = strapi.models[model].allAttributes;
return data;
},
async getProductModel(ctx) {
ctx.params['model'] = "product"
return this.getModel(ctx)
},
//define all endpoints you need, like maybe a Page content type
async getPageModel(ctx) {
ctx.params['model'] = "page"
return this.getModel(ctx)
},
//finally I ended up writing a `allModels` handler
async getAllModels(ctx) {
Object.keys(strapi.models).forEach(key => {
//iterate through all models
//possibly filter some models
//iterate through all fields
Object.keys(strapi.models[key].allAttributes).forEach(fieldKey => {
//build the response - iterate through models and all their fields
}
}
//return your desired custom response
}
Comments & questions welcome
This answer pointed me in the right direction, but strapi.models was undefined for me on strapi 4.4.3.
What worked for me was a controller like so:
async getFields(ctx) {
const model = strapi.db.config.models.find( model => model.collectionName === 'clients' );
return model.attributes;
},
Where clients is replaced by the plural name of your content-type.
I am trying to create an Elasticsearch MLT query using NEST's object initializer syntax. However, the final query when serialized, is ONLY missing the MLT part of it. Every other query is present though.
When inspecting the query object, the MLT is present. It's just not getting serialized.
I wonder what I may be doing wrong.
I also noticed that when I add Fields it works. But I don't believe fields is a mandatory property here that when it is not set, then the MLT query is ignored.
The MLT query is initialized like this;
new MoreLikeThisQuery
{
Like = new[]
{
new Like(new MLTDocProvider
{
Id = parameters.Id
}),
}
}
MLTDocProvider implements the ILikeDocument interface.
I expect the serialized query to contain the MLT part, but it is the only part that is missing.
This looks like a bug in the conditionless behaviour of more like this query in NEST; I've opened an issue to address. In the meantime, you can get the desired behaviour by marking the MoreLikeThisQuery as verbatim, which will override NEST's conditionless behaviour
var client = new ElasticClient();
var parameters = new
{
Id = 1
};
var searchRequest = new SearchRequest<Document>
{
Query = new MoreLikeThisQuery
{
Like = new[]
{
new Like(new MLTDocProvider
{
Id = parameters.Id
}),
},
IsVerbatim = true
}
};
var searchResponse = client.Search<Document>(searchRequest);
which serializes as
{
"query": {
"more_like_this": {
"like": [
{
"_id": 1
}
]
}
}
}
I am trying to write a query to sort out documents based on descending dates ...{sort: {paymentDate: -1 }} order. The first time the query runs, the query section {sort: {paymentDate: -1 }} seems get ignored!
However when I refresh the page in the browser, the query section {sort: {paymentDate: -1 }} is applied, and the query displays in the correct sort order.
I need to know how to correct this issue!
Find below the contents of my document after I run the recipientsDetails.find().fetch(); query in the browser console:
0:
payersUserId: "hbieZBFNE53GpE8LP"
paymentDate: "2019-02-11 02:37:05"
payersNumber: "+25478887633"
paymentStatus: "Failed"
recipientNumber: "+25478887633"
_id: "eFShDRzp9JM9ejG5S"
1:
payersUserId: "hbieZBFNE53GpE8LP"
paymentDate: "2019-02-08 16:02:25"
payersNumber: "+2547078887633"
paymentStatus: "Failed"
recipientNumber: "+25478887633"
_id: "SnpNwsx49mZfPNSg7"
2:
payersUserId: "hbieZBFNE53GpE8LP"
paymentDate: "2019-02-08 15:00:02"
payersNumber: "+254707888633"
paymentStatus: "Failed"
recipientNumber: "+25478087703"
_id: "ZHWSiRBYk2xoZvDzb"
The above results is also the desired sorted order.
Perhaps the below helper code might shade some light.
../client/main.js
Template.paymentB2C.helpers({
'enableButton': function () {
var enableButtonStatusArray = [];
var userIdCode = Meteor.userId();
var phoneNumber = Meteor.users.findOne({_id: userIdCode }, { fields: { "profile.telephoneNumber": 1 } } );
var usersPhoneNumber = phoneNumber.profile.telephoneNumber;
var selectedRecipientDetails = recipientsDetails.find( { $or: [ { payersNumber: usersPhoneNumber }, { recipientNumber: usersPhoneNumber } ] },
{ fields: {
"payersUserId": 1,
"paymentDate": 1,
"paymentStatus": 1,
"_id": 1
} }).fetch();
selectedRecipientDetails.forEach((user) => {
payersUserId = user.payersUserId;
paymentDate = user.paymentDate;
paymentStatus = user.paymentStatus;
_id = user._id;
if(paymentStatus === "Failed"){
enableButtonStatusArray.push({
paymentStatus: paymentStatus,
paymentDate: paymentDate,
_id: _id
});
}
else if(paymentStatus === "Passed"){
enableButtonStatusArray.push({
paymentStatus: paymentStatus,
paymentDate: paymentDate,
_id: _id});
}
Session.set('enableButtonStatusArray2', enableButtonStatusArray );
});
var enableButtonStatusArrayForPrint = Session.get('enableButtonStatusArray2');
return enableButtonStatusArrayForPrint;
}
});
Note that the query here lacks a ...{sort: {paymentDate: -1 }} function.
Find below my Router code:
../client/main.js
Router.route('/paymentB2C', {
name: 'paymentB2C',
template: 'paymentB2C',
waitOn: function(){
return Meteor.subscribe('pendingPayments')
}
});
This leads to my Meteor.subscribe('pendingPayments') publish function:
../server/main.js
Meteor.publish('pendingPayments', function pendingPayments(){
return recipientsDetails.find({}, {sort: {paymentDate: -1 }});
});
Note that here is where I have the sort function.
Can someone explain why when codes first runs, the sort is ignored and the the document is randomly sorted, however is sorted out as designed (correctly) after hitting refresh in the browser?
Looking forward to your help.
Ideally, you should sort the data on the client-side query after you subscribe, instead of sorting it in the publish method.
The reason is that if the client subscribes to more than one publish function which will publish data from the same collections, your find query in the client-side will have access to the data from both publish as well as sort won't be effective. Moreover, publish is something which will grant data access to the subscriber and if the mini-mongo on the client side already has the data, it won't sync the data unless new data arrives.
Hence, you should always do sort and filter in your find queries on the client side as well.
Also, I notice that the format of the paymentDate field is not a 'Date'. It should ideally be of the Date format and should look something like ISODate("2019-02-11T02:37:05.000Z") instead of String format "2019-02-11 02:37:05". So if the sorting on the client side is also not working, try saving the paymentDate in the database as Date instead as a String.
I am trying to work Ember with Parse.com using
ember-model-parse-adapter by samharnack.
I add added a function to make multiple work search(like search engine) for which I have defined a function on cloud using Parse.Cloud.define and run from client.
The problem is the Array that my cloud response returns is not compatible with Ember Model because of two attributes they are __type and className. how can I modify the response to get response similar to that i get when I run a find query from client. i.e without __type and className
Example responses
for App.List.find() = {
"results":[
{
"text":"zzz",
"words":[
"zzz"
],
"createdAt":"2013-06-25T16:19:04.120Z",
"updatedAt":"2013-06-25T16:19:04.120Z",
"objectId":"L1X55krC8x"
}
]
}
for App.List.cloudFunction("sliptSearch",{"text" : this.get("searchText")})
{
"results":[
{
"text":"zzz",
"words":[
"zzz"
],
"createdAt":"2013-06-25T16:19:04.120Z",
"updatedAt":"2013-06-25T16:19:04.120Z",
"objectId":"L1X55krC8x",
"__type" : Object, //undesired
"className" : "Lists" //undesired
}
]
}
Thanks Vlad something like this worked for me for array
resultobj = [];
searchListQuery.find({
success: function(results) {
for( var i=0, l=results.length; i<l; i++ ) {
temp = results.pop();
resultobj.push({
text: temp.get("text"),
createdAt: temp.createdAt,
updatedAt: temp.updatedAt,
objectId: temp.id,
words: "",
hashtags: ""
});
}
In your cloud code before you make any response, create and object and extract from it the attributes/members you need and then response it. like so:
//lets say result is some Parse.User or any other Parse.Object
function(result)
{
var responseObj = {};
responseObj.name = responseObj.get("name");
responseObj.age = responseObj.get("age");
responseObj.id = responseObj.id;
response.success(responseObj);
}
on the response side you will get {"result": {"name": "jhon", "age": "26", "id": "zxc123s21"}}
Hope this would help you