I create an expense collection in firebase but when I access it in other screen using provider every time I add new item It duplicate the previous item as I continue inserting items it duplicate them?
final summaryDataExpense = Provider.of<ExpensesData>(context).expenseList;
final filterByYearExpense = summaryDataExpense
.where((element) =>
DateTime.parse(element['itemDate']).year == currentYear)
.toList();
var totalExpenses = filterByYearExpense.map((e) => e['itemPrice']).toList();
totalExpenses return wrong length of the items existed
You need to replace type of expenseList from List to Set.
Set will take care of the duplicates.
Related
I want to get documents from Firestore with the conditions. There are 5 conditions where 4 of which are optional. If I use where with streamBuilder, I have to create many indexes.
So, I'm going to try this method, I want to get your opinion about this.
Create a list for the store DocumentSnapshot
List<DocumentSnapshot> documents = [];
Store the snapshot to List
documents = streamSnapshot.data.docs;
Filter data like this:
if (searchText.length > 0) {
documents = documents.where((element) {
return element
.get('Title')
.toString()
.toLowerCase()
.contains(searchText.toLowerCase());
}).toList();
}
I have two list of data stored in
1. final profiles = context.watch<ProfilesBloc>().state.profiles;
2. final users= context.watch<UsersBloc>().state.users;
I want to build the list with the only whose profile.id matches the user.id
I tried by if (user.id == profiles.id) but it's not working
any help?
var newUser = users.where((user) => user.id.toLowerCase().contains(profiles.id.toLowerCase()).toList();
you can basically use this method to check a condition to create a new list. Feel free to alter the codes as per your requirements.
I have a list of strings, when I click a button I want to generate a new list with a specific number of items from my original list of strings.
I'm able to generate a random list with no repeating items but the number of items that returns is random. For example I want a new list of 5 items, sometimes it returns with 2 items other times 4 etc.
var randomList = new List.generate(
5, (_) => originalList[Random().nextInt(originalList.length)]).toSet().toList();
I've found lots of info for returning 1 random item, but nothing about multiples.
EDIT:
Thank you everyone for the responses, I was able to fix my problem by using shuffle like so
var randomList = (originalList..shuffle()).take(5).toList();
Your method of getting random items out of the original list will result in duplicates, which are then eliminated when you call .toSet(), which is why you get lists of varying lengths.
Instead of calling .toSet() to prevent duplicates, we need to be sure that no duplicates are chosen in the first place.
One way of doing that would be to generate a list of numbers from 0 up to originalList.length - 1, then shuffle them, and then choose the first n numbers from that list, and map them to values from original list.
void main() {
List<String> originalList = ["hello", "what", "goodbye", "Test", "Apple", "Banana"];
List<int> indices = List<int>.generate(originalList.length, (i) => i);
indices.shuffle();
int newCount = 3;
List<String> randomList = indices.take(newCount).map((i) => originalList[i]).toList();
print(randomList);
}
This method is efficient, and has a worst case performance of O(n), assuming dart has an efficient shuffle() implementation (which I'm sure it does).
The problem here is the list generates duplicates nonetheless.
var randomList = new List.generate(5, (_) => originalList[Random().nextInt(originalList.length)])
The list could contain [dello, kello, hello, gello, hello]
(for example, assume items are taken from the original list)
Now performing .toSet() on this will remove the duplicate hello from the list, this is what causes the list size to be random. In this instance it's two duplicates, but later on it could have more.
A simple solution for this would be
var randomList = [];
List.generate(5, (_) {
var randomString = originalList[Random().nextInt(originalList.length)];
while (randomList.contains(randomString)) {
randomString = originalList[Random().nextInt(originalList.length)];
}
randomList.add(randomString);
});
I'm trying to fetch a list of documents (documentID) from Firestore and add it to a List. I have seen some options but since I am a little new in this area, perhaps the obvious is becoming difficult for me. And I don't know exactly where in the code those lines should go, for example in an initState.
This is one of the options that I have chosen, but it only generates instances and not the name of the documents as such.
final QuerySnapshot result =
await Firestore.instance.collection('submits').getDocuments();
final List<DocumentSnapshot> documents = result.documents;
List<String> myListString = []; // My list I want to create.
myListString.add(documents); // The way I try to add the doc list to my String list.
Example the data base. I want to get a list of the document ID to a List-String-
enter image description here
And if possible, you could tell me if there is an analogous way to apply it to obtain a List but in the case of two or more collections.
It seems like what you want is a list of the document ids, right?
If so, this should work:
final QuerySnapshot result =
await Firestore.instance.collection('submits').getDocuments();
final List<DocumentSnapshot> documents = result.documents;
List<String> myListString = []; // My list I want to create.
documents.forEach((snapshot) {
myListString.add(snapshot.documentID)
});
I want to update the itemsToUpdate collection.
This collection is already used in a query thus the resulting entities are already tracked in the context local property.
What is the most efficient way of overriding properties of the context.items.Local property from the itemsToUpdate collection?
private async Task<IEnumerable<item>> GetitemsAsync(IEnumerable<item> itemIds)
{
return await context.items.Where(t => itemIds.Select(x => x.Id).Contains(t.Id)).ToListAsync();
}
public async Task Update(...)
{
// Update
var queryUpdateitems = await GetitemsAsync(itemsToUpdate);
bool canUpdate = queryUpdateitems.All(t => t.UserId == userId);
if (!canUpdate)
{
throw new NotAuthorizedException();
}
else
{
// update here the itemsToUpdate collection
}
context.SaveChangesAsync();
}
In your case, you know that you have to update all these items, you just want to make sure that current user can update all items (by comparing Item.UserId). Instead of fetching all the existing items from database to make the check, you can query database to give result of the check and then you can just send update to database if check is true.
var itemIds = itemsToUpdate.Select(x => x.Id).ToList();
var canUpdate = await db.Blogs.Where(b => itemIds.Contains(b.Id)).AllAsync(t => t.UserId == userId);
if (canUpdate)
{
db.UpdateRange(itemsToUpdate);
}
else
{
throw new NotSupportedException();
}
await db.SaveChangesAsync();
Here, you have to make list of itemIds first because EF cannot inline list of items in a query and will do evaluation on client otherwise. That means EF is fetching whole table. Same is true for your GetitemsAsync method. It also queries whole table. Consider creating itemIds locally in that method too.
Once you pass in List<int> in the method EF will be happy to inline it in query and for query of canUpdate it will sent single query to database and fetch just true/false from database. Then you can use UpdateRange directly since there are nomore tracking records. Since it does not fetch all items from database, it will be faster too.