I'm in the process of building a community connector and am scratching my head; the documentation states:
getData()
Returns the tabular data for the given request.
Request
#param {Object} request A JavaScript object containing the data
request parameters.
The request parameter contains user provided values and additional
information that can be used to complete the data request. It has the
following structure:
{ "configParams": object, "scriptParams": {
"sampleExtraction": boolean,
"lastRefresh": string }, "dateRange": {
"startDate": string,
"endDate": string }, "fields": [
{
object(Field)
} ] }
I've correctly setup getConfig() (at least, my configurations are requested from the user), but my getData function is not being passed a configParams object. Here's my code.
function getConfig(request) {
var Harvest = HarvestService({
token: getHarvestAuthService().getAccessToken()
});
var accounts = Harvest.accounts.list();
var options = accounts.map(function(account) {
return {
label: account.name,
value: account.id
};
});
var config = {
configParams: [
{
type: 'SELECT_SINGLE',
name: 'harvestAccountId',
displayName: 'Harvest Account ID',
helpText: 'The ID of the Harvest Account to pull data from.',
options: options
}
],
dateRangeRequired: true
};
return config;
}
function getData(request) {
var startDate = request.dateRange.startDate;
var endDate = request.dateRange.endDate;
var accountId = request.configParams.harvestAccountId;
var harvestAuthService = getHarvestAuthService();
var Harvest = HarvestService({
token: harvestAuthService.getAccessToken(),
account: accountId
});
var fieldKeys = request.fields.map(function(field) { return field.name; });
var entries = Harvest.entries.list({
startDate: new Date(startDate),
endDate: new Date(endDate)
});
var rows = entries.map(entryToRow);
return {
schema: request.fields,
rows: rows,
cachedData: false
};
}
When I test/debug, I can select an Account at the config step, the schema is correctly returned, but I get the following exception when I try and add a widget to the report:
Script error message:
TypeError: Cannot read property "harvestAccountId" from undefined.
Script error cause: USER Script
error stacktrace: getData:244
Any advice greatly appreciated.
Found out the problem - the issue was that the value attribute of the option was a number, but it MUST be a string:
https://developers.google.com/datastudio/connector/reference#getconfig
Leaving this here in case anyone else gets stuck on this. Your config select options for your Data Studio Community Connector must have strings for both the label and the value, and nobody will coerce them for you. Fix was this:
var options = accounts.map(function(account) {
return {
label: account.name,
value: account.id + ''
};
});
Usually, request.configParams is undefined when there are no configuration values passed from the user config.
When testing the connector, are you selecting a value in the dropdown for harvestAccountId?
If you plan to share this connector with other users, it might be a good idea to have a default value for harvestAccountId in case the user does not select an option.
You can use Apps Script logging to see the response for getConfig() to ensure that right values are getting passed for options. Then you can also log the request for getData() to have a better understanding of what exactly is getting passed in the request.
Leaving this in case it helps anyone, note that the config params in the UI although they have a placeholder value need to be physically populated to appear in the request. Indeed, if none of these are filled in the configParams value does not appear in the request object.
Related
I'm new in react-admin and I'm trying to create a new admin panel for my old API.
So when my data provider do API calls it causes me this error:
The response to 'getList' must be like { data : [...] }, but the received data is not an array. The dataProvider is probably wrong for 'getList'
The responses of my old API has various data fields like { 'posts': [] } or { 'users': [] }. How can I use these name of fields instead of { 'data': [] } ?
The 'data' in this case just refers to the type of information that should be retuned, not the name of the object.
Within your API, you can simply return a list in the following form:
const posts = [
{
"id":1,
"name":"post1"
},
{
"id":2,
"name":"post2"
},
];
return JSON.stringify(posts);
Then return that 'posts' object in your response and don't forget to set the expected ContentRange headers.
Not sure what language you are using, but the principle above should be easy enough to follow and apply in any language.
I'm using react-native-gifted-chat in my react-native app. As I shown in this image, there is same message displayed multiple time and message: Yes getting new msg 's place is also varied from it's actual position.
My issue is same as this. Can anyone please help me to solve this.
Thank you in advance.
I got a solution of my question. #Ron you are right but in my case the issue is different. I solved it by change my format of parameters. It took different format and I passed different so they conflicted each other. Here is the solution it may useful to others.
parse = snapshot => {
const { timestamp: numberStamp, text } = snapshot.val();
const { key: _id } = snapshot;
const createdAt = moment(snapshot.val().createdAt, "DD/MM/YYYY hh:mm:ss");
const user = { };
var temp_data = snapshot.val()
if(snapshot.val().name == this.state.temp_logged_name) {
user._id = 1;
user.name = temp_data.name;
user.avatar = temp_data.avatar;
}
const message = {
_id,
createdAt,
text,
user,
};
return message;
};
I had encountered this issue as well. I had set up react-native-gifted-chat on my mobile app. And at the other end I had set up a simple HTML page with a script to initialise the Websocket connection and send messages on the onsend event. What I had realised later that while the unique id was getting generated at the app end (because the id was being generated by the library itself), nothing of such sort existed at the other end.
Basically, this weird behaviour crops up when a unique id _id is missing for a message. Each message must have at least the following properties while executing GiftedChat.append(previousMessages, messages).
{
_id: 1,
text: 'Hello developer',
createdAt: new Date(),
user: {
_id: 2
}
}
There could be two reasons behind it,
1) Each message should be passed a unique id, so just use uuidv4 npm package and append it to _id prop of the object.
Example:
messages: GiftedChat.append(previousState.messages, {
_id: uuidv4(), // or use Math.round(Math.random() * 1000000)
text: text,
createdAt: new Date(),
user: {
_id: 2,
name: "React Native",
avatar: "https://placeimg.com/140/140/any"
},
image: attachment
})
2) Second possibility could be on the gateway you are using to initiate the chat between users. So, some gateways have known issues to repeat the message multiple times. You could to string comparison each time a new message is received and pushed to the chat screen, however it is not advised to do this.
I figured this out by simply applying the filter to the incoming message in useLayout Effect:
useLayoutEffect(() => {
db.collection('Chats').doc(docID).collection('messages').orderBy("createdAt", "desc").onSnapshot(snapshot => {
setMessages(
prev =>
prev
.filter((ftr,index,self) => ftr?.user?._id !== loginUser?.id) //login user id is the current user's id you can do the same for recieved messages
.concat
(snapshot.docs.map(doc => doc.data({
_id: doc?.id,
user: doc.data().user,
text: doc.data().text,
createdAt:new Date(doc.data().createdAt),
})
))
)
})
},[])
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
EDIT: Since I wasn't able to find a correct solution, I changed the
application's structure a bit and posted another question:
Mongoose - find documents not in a list
I have a MEAN app with three models: User, Task, and for keeping track of which task is assigned to which user I have UserTask, which looks like this:
const mongoose = require("mongoose");
const autopopulate = require("mongoose-autopopulate");
const UserTaskSchema = mongoose.Schema({
completed: { type: Boolean, default: false },
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
autopopulate: true
},
taskId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Task",
autopopulate: true
}
});
UserTaskSchema.plugin(autopopulate);
module.exports = mongoose.model("UserTask", UserTaskSchema);
In my frontend app I have AngularJS services and I already have functions for getting all users, all tasks, and tasks which are assigned to a particular user (by getting all UserTasks with given userId. For example:
// user-task.service.js
function getAllUserTasksForUser(userId) {
return $http
.get("http://localhost:3333/userTasks/byUserId/" + userId)
.then(function(response) {
return response.data;
});
}
// task-service.js
function getAllTasks() {
return $http.get("http://localhost:3333/tasks").then(function(response) {
return response.data;
});
}
Then I'm using this data in my controllers like this:
userTaskService
.getAllUserTasksForUser($routeParams.id)
.then(data => (vm.userTasks = data));
...and because of autopopulate plugin I have complete User and Task objects inside the UserTasks that I get. So far, so good.
Now I need to get all Tasks which are not assigned to a particular User. I guess I should first get all Tasks, then all UserTasks for a given userId, and then make some kind of difference, with some "where-not-in" kind of filter.
I'm still a newbie for all the MEAN components, I'm not familiar with all those then()s and promises and stuff... and I'm really not sure how to do this. I tried using multiple then()s but with no success. Can anyone give me a hint?
You can do at server/API side that will more efficient.
In client side, if you want to do then try below
var userid = $routeParams.id;
userTaskService
.getAllTasks()
.then((data) => {
vm.userTasks = data.filter(task => task.userId !== userid)
});
I have the following code:
import { Meteor } from 'meteor/meteor';
import { Items } from './collection';
if (Meteor.isServer) {
Meteor.publish('items', function(options, owner) {
let selector = {
$and: [{ ownerId: owner}]
}
return Items.find(selector, options);
});
}
And on the client side I have:
this.subscribe('items', () => [{
limit: this.getReactively('querylimit'),
sort: {dateTime: -1}
},
this.getReactively('ownerId')
]);
The above does not return any results. However, when I change the return statement to the following, it works!
return Items.find({ ownerId: '7QcWm55wGw69hpuy2' }, options); //works !!!
I'm not very familiar with Mongo/Meteor query selectors. Passing the query as a variable to Items.find() seems to be messing something up. Can someone please help me figure this out!
Thanks
You are trying to pass a function as the selector, which won't work. Functions can't be serialized and sent from the client to the server. Instead you need to evaluate the options and the owner separately. Here's an example:
var owner = this.getReactively('ownerId');
var options = {
limit: this.getReactively('querylimit'),
sort: {dateTime: -1}
};
this.subscribe('items', options, owner);
Note that the published documents will not arrive in sorted order, so unless you are using a limit, the sort doesn't help here.
Also note that if you need the subscription to rerun after the owner or query limit change, you'll need to subscribe inside of an autorun.
Here's a start on an improved implementation:
Meteor.publish('items', function(options, owner) {
// DANGER! Actually check this against something safe!
check(options, Object);
// DANGER! Should any user subscribe for any owner's items?
check(owner, Match.Maybe(String));
// Publish the current user's items by default.
if (!owner) {
owner = this.userId;
}
return Items.find({ ownerId: owner }, options);
});
How can I post an array of Schema.Types.ObjectId (s) to MongoDB? I'm trying to create User Groups, which is a group of the 'User' Model e.g.
var UserGroup = new Schema({
users: [{
type: Schema.Types.ObjectId,
ref: 'User'
}]
});
New UserGroup Function
module.exports.create = function(request, response) {
var group = new UserGroup({
users = request.body.users
});
group.save(function(error) {
if(error) { throw error; } else { response.send('Group Created Successfully.');
});
};
I'm currently using Postman to test the functionality, how exactly should the data be posted?
As a Javascript array i.e ['A_USER_ID', 'A_USER_ID'] ?
Thanks!
#Answer
I was using the older syntax of the select() function, and therefore was passing invalid parameters to the $push function. When sending the request, I simply pass the ObjectIds as id,id,id and once they get to the server, simply put it into an array using var my_array = request.body.users.split(','); and then push it to the database using the following:
$push: { users: { $each: my_array } }
I hope this was helpful, the documentation isn't particularly clear on this matter.