my backend is made with parse.com Now I experienced in the Parse.com Analytics-Section the Tab "Slow Queries". Nice feature to see how your queries are performing.
Now what I see there is that there are queries of mine with empty where clauses you can see it here:
Users where:{ facebookID: ... }
Friends where:{ user: ... }
Friends where:{ objectId: ... }
Users where:{}
Friends_Rel where:{ friend: ..., user: ... }
Friends_Rel where:{}
Now my question is why are there empty where clauses? Because I assume that this Query results in an error and it is not wanted by me I think.
I always build my queries either like this:
var query = new Parse.Query("Friends_Rel");
query.equalTo("friend", friendID);
query.equalTo("user", userID);
query.find({
success: function(results) {
},
error: function(error) {
}
});
or like this:
var query = new Parse.Query("Users");
query.get(objectID, { // Gets row you're trying to update
success: function(row) {
},
error: function(row, error) {
}
});
Is there any explanation for this clauses where they could come from? Does the .get Method results in where:{}? I am not sure...
Closing as sunsetting parse.com
Related
I'm working on a vue3 project using #vue/apollo-composable and #graphql-codegen.
My index page does a search query. Each result from that query has a tile made on the page. I'm expecting the tile queries will be answered by the cache, but instead, they always miss.
At the page level I do this query:
query getTokens($limit: Int!) {
tokens(limit: $limit) {
...tokenInfo
}
}
Inside of the tile component I execute:
query getToken($id: uuid!){
token(id: $id) {
...tokenInfo
}
}
The fragment looks like this:
fragment tokenInfo on token {
id
name
}
Expectation: The cache would handle 100% of the queries inside the tile components. (I'm hoping to avoid the downfalls of serializing this data to vuex).
Reality: I get n+1 backend calls. I've tried a bunch of permutations including getting rid of the fragment. If I send the getToken call with fetchPolicy: 'cache-only' no data is returned.
The apollo client configuration is very basic:
const cache = new InMemoryCache();
const defaultClient = new ApolloClient({
uri: 'http://localhost:8080/v1/graphql',
cache: cache,
connectToDevTools: true,
});
const app = createApp(App)
.use(Store, StateKey)
.use(router)
.provide(DefaultApolloClient, defaultClient);
I'm also attaching a screenshot of my apollo dev tools. It appears that the cache is in fact getting populated with normalized data:
Any help would be greatly appreciated! :)
I've gotten this worked out thanks to #xadm's comment as well as some feedback I received on the Vue discord. Really my confusion is down to me being new to so many of these tools. Deciding to live on the edge and be a vue3 early adopter (which I love in many ways) made it even easier for me to be confused with the variance in documentation qualities right now.
That said, here is what I've got as a solution.
Problem: The actual problem is that, as configured, Apollo has no way to know that getTokens and getToken return the same type (token).
Solution: The minimum configuration I've found that resolves this is as follows:
const cache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
token(_, { args, toReference }) {
return toReference({
__typename: 'token',
id: args?.id,
});
},
},
},
},
});
However, the feels.... kinda gross to me. Ideally, I'd love to see a way to just point apollo at a copy of my schema, or a schema introspection, and have it figure this out for me. If someone is aware of a better way to do that please let me know.
Better(?) Solution: In the short term here what I feel is a slightly more scalable solution:
type CacheRedirects = Record<string, FieldReadFunction>;
function generateCacheRedirects(types: string[]): CacheRedirects {
const redirects: CacheRedirects = {};
for (const type of types) {
redirects[type] = (_, { args, toReference }) => {
return toReference({
__typename: type,
id: args?.id,
});
};
}
return redirects;
}
const cache = new InMemoryCache({
typePolicies: {
Query: {
fields: {
...generateCacheRedirects(['token']),
},
},
},
});
If anyone has any improvements on these, please add a comment/solution! :)
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.
I'm having a hard time figuring out how to retrieve a set of stories using a tag name (TagName) as a filter. I have tried the following, but it always returns an empty store (the alert at the bottom returns []). Can someone help me figure out what I'm doing wrong?
var storyStore = Ext.create('Rally.data.wsapi.Store', {
model: "User Story",
fetch: true,
filters: [
{
property: 'Tags.Name',
operator: '=',
value: 'TagName'
}
]
});
storyStore.load({
callback: function(records, operation) {
if(!operation.wasSuccessful()) {
//process records
}
}
});
alert(JSON.stringify(storyStore.getRecords()));
Any help would be greatly appreciated!!!
This is due to the asynchronous nature of the store.load call. Your store and filters look totally right. Try putting your alert inside of the if statement within your callback. I bet you'll find there is data in there then:
storyStore.load({
callback: function(records, operation) {
if(operation.wasSuccessful()) {
alert(JSON.stringify(storyStore.getRecords()));
}
}
});
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.
How would I use Backbones fetch to deal with callback results that contain a cursor? I'm going to use this simple example of a book that is fetching pages.
var Book = Backbone.Collection.extend({
model: Page,
recursiveFetch: function(cursor) {
this.fetch({
url: 'book/pages',
data: {
cursor: {cursor here};
},
success: function(response) {
if (response.cursor) {
this.recursiveFetch(response.cursor);
}
}
});
}
})
I need to be able to use fetch to keep fetching until the response doesn't contain a cursor. It should keep adding page models, but not replacing and overwriting them. It needs to do something like the example above, though I'm not sure of the best way to implement it.
I think that all you need to do is add in a {remove: false} into your fetch options. Its also worth mentioning that the this context of your success function may not be the collection, so you might want to pass it into the success function as a parameter. The end result would be:
recursiveFetch: function(cursor) {
this.fetch({
remove:false, // prevents removal of existing models
url: 'book/pages',
success: function(collection, response) {
if (response.cursor) {
collection.recursiveFetch(response.cursor);
}
}
});
}
The fix is very simple: add cursor to the parameters only when it's present. In other cases (i.e. the first time) make a normal request with the rest of the parameters.
var CursorCollection = Backbone.Collection.extend({
fetchAll: function(cursor) {
var params = {
// if you have some other request parameters...
};
// if we have a cursor from the previous call, add it to the parameters
if (cursor) { params.cursor = cursor; }
this.fetch({
remove: false,
data: params,
success: function(collection, response) {
if (response.cursor) {
return collection.fetchAll(response.cursor);
}
}
});
}
});
Then the first time you call it collection.fetchAll() and it recurses until it gets a response without a cursor.
Note, that the remove: false parameter is very important to accumulate the results as pointed out by #dcarson.