Angularfire2 + Firestore query result with reference - angularfire2

I have few hundreds docs in a collection. And few of them are corrupted and I want to delete them. I know how to find the corrupted documents and I get them as a result of a query. But it's just a data, there is no document ID or anything.
So my question is, how to delete documents which I receive in query? Or is there another way how to delete documents based on some property?
getData(target) {
return this.afs.collection('someCollection', ref => {
let query: firebase.firestore.CollectionReference | firebase.firestore.Query = ref;
query = query.where('label', '==', target);
return query;
});
}
this.dataService.getData('CorruptedLabel').valueChanges().subscribe(resp => {
console.log('resp', resp); // Here I get and array of objects
// I would like to go through that array and call delete() on each item
});

You can get the firestore document reference and delete the doc
this.dataService.getData('CorruptedLabel').snapshotChanges().subscribe(snapshots
=> {
snapshots.forEach(snapshot => {
if(snapshot){
this.afs.collection('someCollection').doc(snapshot.payload.doc.id).delete();
}
}
});

Related

GraphQL only returning one item from array instead of all items

I have a GraphQL query which is meant to return a full array list containing 9 items, but it's only returning 1 item. This is an Array of Objects.
If I console log data.dataJson it returns the first Object in the array as an Object, not Array...
I'm new to using GraphQL so any pointers would be appreciated!
Query
export const ProjectsQuery = graphql`
query IndexQuery {
dataJson {
title
img
type
category
url
}
}
`;
So the issue was down to having an unnamed array in the JSON. Changing to the following fixed the issue:
{
"projects": [
{
...
}
]
}

Apollo TypePolicies: Custom Merge function in cached field breaks pagination

I want to be able to overwrite one of the fields in ListItem when a ListItem of the same Id comes in from my middleware. The issue is that if I create a custom merge function for any field it makes my pagination stop working. The new data is not properly merged in the list of results.
When I console.log in the resultPagination merge-function it seems to merge properly. But, in my interface where I am calling resultPagination the state is stuck on loading. So, in other words, I can fetch the first page of results, but when I call fetchMore I get stuck on loading.
If I remove the custom merge function in ListItem the pagination starts working properly again. If I don't define a merge for any specific fields in ListItem, but just define merge as true the pagination works properly, and the ListItem is updated, but the values in the ListItem are completely overwritten ( I just want to change the value of one field ).
How do I define a custom Merge function for ListItem while still allowing Pagination to work in the result Pagination?
Below I give an example of how my structure is looking right now:
export const typePolicies: TypePolicies = {
ListItem: {
fields: {
tags: {
merge: (existing: Tag[] = [], incoming: Tag[]) => {
return !!incoming ? incoming : existing;
}
}
}
},
Query: {
fields: {
resultPagination: {
keyArgs: ["query", "sortByDate", "specificFields"],
merge: (existing, incoming, args) => {
if (!incoming) return existing;
if (args.args.offset === 0) return incoming;
const existingListItemLists: ListItem[][] =
existing?.articleSummaries ?? [];
const incomingListItemLists: ListItem[][] =
incoming?.articleSummaries ?? [];
return {
...incoming,
results: [...existingListItemLists, ...incomingListItemLists]
};
}
}
}
}
};

Different query for same __typename data returns undefined on Apollo Graphql from cache

I am fairly new to Apollo and Graphql and I quite don't know what I am doing wrong. I will try to explain my problem with some simplified code but if I am missing some information please let me know and I will update it.
I have an Apollo client instance consuming an external (Directus CMS) graphql API not modifiable by me.
The thing is I am querying a paginated (infinite scroll) of posts with offset and limit variables and the data returned is correct. I am using the following typePolicy in order to merge results arrays in my inMemoryCache. This code is from an example in the Apollo Docs:
posts {
const merged = existing ? existing.slice(0) : [];
const postIdToIndex = Object.create(null);
if (existing) {
existing.forEach((post, index) => {
postIdToIndex[readField("id", post)] = index;
});
}
incoming.forEach((post) => {
const id = readField("id", post);
const index = postIdToIndex[id];
if (typeof index === "number") {
// Merge the new post data with the existing post data.
merged[index] = mergeObjects(merged[index], post);
} else {
// First time we've seen this post in this array.
postIdToIndex[id] = merged.length;
merged.push(post);
}
});
return merged;
}
and this is a simplified version of my query:
query($offset: Int $limit: Int) {
posts(limit: $limit offset: $offset) {
id
name
}
}
With this merge function and query I get my pagination right and everything loads correctly. But when I try to query a single instance of post that queries also additional fields from it with the following query:
query($offset: Int $limit: Int $post_id: Int) {
posts(filter:{id:{_eq: $post_id}}) {
id
name
other_data
}
}
This returns undefined constantly when using useQuery() although i can see that is coming through my merge funtion and merging objects with the mergeObjects() function. If I use a fetchPolicy of no-cache in this query, the data returns correctly so it has something to do with the cache.
I hope someone can lead me in the right direction so I can fix this problem.
Thank you everyone in advance!!

filter sensible data from graphql response on strapi

There are some information in my models, that should only be visible for some users. How can I alter the GraphQL response, in order to make sure that no sensible data is leaking the server?
I had partly success by overriding the find method in the controller of the model. I can alter/remove fields like this:
async find(ctx) {
let entities;
if (ctx.query._q) {
entities = await strapi.services.article.search(ctx.query);
} else {
entities = await strapi.services.article.find(ctx.params);
}
return entities.map(entity => {
// filter information here e.g.
entity.name = ""; // name will be always empty in the GraphQL response
return entity;
});
}
But, for nested models I cannot filter it. Example:
Article has many Documents. Some Documents should not be visible, but the GraphQL response does not respect if I remove the data:
//...
return entities.map(entity => {
// filter information here e.g.
entity.name = "";
entity.documents = []; // does not have any effect. Documents are still in the GraphQL response
return entity;
});

Angular Meteor objects not acting as expected

I am working with Angular Meteor and am having an issue with my objects/arrays. I have this code:
angular.module("learn").controller("CurriculumDetailController", ['$scope', '$stateParams', '$meteor',
function($scope, $stateParams, $meteor){
$scope.curriculum = $meteor.object(CurriculumList, $stateParams.curriculumId);
$scope.resources = _.map($scope.curriculum.resources, function(obj) {
return ResourceList.findOne({_id:obj._id})
});
console.log($scope.resources)
}]);
I am attempting to iterate over 'resources', which is a nested array in the curriculum object, look up each value in the 'ResourceList' collection, and return the new array in the scope.
Problem is, sometimes it works, sometimes it doesnt. When I load up the page and access it through a UI-router link. I get the array as expected. But if the page is refreshed, $scope.resources is an empty array.
My thought is there is something going on with asynchronous calls but have not been able for find a solution. I still have the autopublish package installed. Any help would be appreciated.
What you're going to do is return a cursor containing all the information you want, then you can work with $meteor.object on the client side if you like. Normally, publishComposite would look something like this: (I don't know what your curriculum.resources looks like)
Use this method if the curriculum.resources has only ONE id:
// this takes the place of the publish method
Meteor.publishComposite('curriculum', function(id) {
return {
find: function() {
// Here you are getting the CurriculumList based on the id, or whatever you want
return CurriculumList.find({_id: id});
},
children: [
{
find: function(curr) {
// (curr) will be each of the CurriculumList's found from the parent query
// Normally you would do something like this:
return ResourceList.find(_id: curr.resources[0]._id);
}
}
]
}
})
This method if you have multiple resources:
However, since it looks like your curriculum is going to have a resources list with one or many objects with id's then we need to build the query before returning anything. Try something like:
// well use a function so we can send in an _id
Meteor.publishComposite('curriculum', function(id){
// we'll build our query before returning it.
var query = {
find: function() {
return CurriculumList.find({_id: id});
}
};
// now we'll fetch the curriculum so we can access the resources list
var curr = CurriculumList.find({_id: id}).fetch();
// this will pluck the ids from the resources and place them into an array
var rList = _.pluck(curr.resources, '_id');
// here we'll iterate over the resource ids and place a "find" object into the query.children array.
query.children = [];
_.each(rList, function(id) {
var childObj = {
find: function() {
return ResourceList.find({_id: id});
}
};
query.children.push(childObj)
})
return query;
});
So what should happen here (I didn't test) is with one publish function you will be getting the Curriculum you want, plus all of it's resourceslist children.
Now you will have access to these on the client side.
$scope.curriculum = $meteor.object(CurriculumList, $stateParams.curriculumId);
// collection if more than one, object if only one.
$scope.resources = $meteor.collection(ResoursesList, false);
This was thrown together somewhat quickly so I apologize if it doesn't work straight off, any trouble I'll help you fix.

Resources