how to use loop inside query on firestore? - firebase

Is it possible to use loop inside query?
Future<void> addServiceConfig(String uid, List<ServiceConfigModel> model) {
_db.collection('users').document(uid).updateData({
'businessDetails':{
'serviceConfig':FieldValue.arrayUnion([
{
for(int i = 0;i <model.length;i++){
if (model[i].inShop != null) 'inShop': model[i].inShop,
if (model[i].inShopAndClientLocation != null)
'inShopAndClientLocation': model[i].inShopAndClientLocation,
if (model[i].clientLocation != null)
'clientLocation': model[i].clientLocation,
'serviceLocations': model[i].serviceLocations,
'subCategoryId': model[i].subCategoryId
}
}
])
}
});
}
I got this error:
[ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: Invalid argument: Instance of '_CompactLinkedHashSet>'

You can't use a loop (or many other statements) inside an expression, like the value of a field. One solution is to pull construct the value outside of the update() all and then pass it in:
//var config = new Map()
var result = new List();
for(int i = 0;i < model.length; i++){
var config = new Map();
if (model[i].inShop != null) config['inShop'] = model[i].inShop;
if (model[i].inShopAndClientLocation != null)
config['inShopAndClientLocation'] = model[i].inShopAndClientLocation;
if (model[i].clientLocation != null)
config['clientLocation'] = model[i].clientLocation;
config['serviceLocations'] = model[i].serviceLocations,
config['subCategoryId'] = model[i].subCategoryId;
result.add(config);
}
_db.collection('users').document(uid).updateData({
'businessDetails':{
'serviceConfig': FieldValue.arrayUnion(result)
}
});

Related

using futures with flutter maps

I have this code which is supposed to loop through images to upload them to firebase, then take their links and put it inside the Product class so the product can have its images link. Then, upload the product too.
The problem is it doesn't wait for the upload to happen to insert its links to the product.
Code
List<String> imgUrls = [];
Future<void> loopThroughMap()async{
_map.forEach((storedImage, inGallery) async {
if (!inGallery && storedImage != null && storedImage.path != null) {
await GallerySaver.saveImage(storedImage.path);
}
String urlString = await FirestoreHelper.uploadImage(storedImage);
imgUrls.add(urlString);
});
}
This function is called in here
`
await loopThroughMap();
print('FINISHED THIS ONE, imgs Urls length ${imgUrls.length}');
for (int i = 0; i < imgUrls.length; i++) {
if (i == 0)
_editedProduct.imageUrl = imgUrls[i];
else if (i == 1)
_editedProduct.imageUrl2 = imgUrls[i];
else if (i == 2)
_editedProduct.imageUrl3 = imgUrls[i];
else if (i == 3) _editedProduct.imageUrl4 = imgUrls[i];
}`
The imgUrls list length is ALWAYS zero.
Could it be a problem with the map.foreach?
Ok, I changed the uploading from the ForEach loop to a for loop, and it works fine!
List<File> _listedImages = [];
Future<void> loopThroughMap(){
_map.forEach((storedImage, inGallery) async {
if (!inGallery && storedImage != null && storedImage.path != null) {
GallerySaver.saveImage(storedImage.path);
}
_listedImages.add(storedImage);
});
}
/////
for(var img in _listedImages){
String url = await FirestoreHelper.uploadImage(img);
imgUrls.add(url);
}
After a lot of iterations, the only variable that was causing the error was the ForEach loop.

Flutter Firebase update will not stop updating node?

I'm searching for an int value in my firebase node and decreasing it. It successfully decreases and prints the correct info to my log once. When I attempt to update the node with the new int it repeats as if it where in a loop. How can I get it to update a single time? Here is my code...
if (vidRank == 1) {
await fb.child('UserVideo/${userid}/Vid1').onValue.listen((Event event){
if (event.snapshot != null){
var vid1id = event.snapshot.value['videoID'].toString();
fb.child('NumberOnes/${vid1id}').onValue.listen((Event onesEvent){
if (onesEvent.snapshot != null){
var onesValue = (onesEvent.snapshot.value['Value'] as int);
final vidValue = onesValue - 1;
print("Inside ${vidValue}");
fb.child('NumberOnes/${vid1id}').update({
'Value': vidValue
});
}
});
}
});
If you only want a single action, use .once()
if (vidRank == 1) {
var event = await fb.child('UserVideo/${userid}/Vid1').once();
if (event.snapshot != null){
var vid1id = event.snapshot.value['videoID'].toString();
var onesEvent = await fb.child('NumberOnes/${vid1id}').once();
if (onesEvent.snapshot != null){
var onesValue = (onesEvent.snapshot.value['Value'] as int);
final vidValue = onesValue - 1;
print("Inside ${vidValue}");
fb.child('NumberOnes/${vid1id}').update({
'Value': vidValue
});
}
}
}
otherwise an update will cause another event for listen(...) and you have a perfect loop.

EntityFramework,Navigation properties' Changes cannot be SAVE

//Hi,the following code snippet ,I want to Change the model and it's related entities according to the model's naviagation properties,But only affected the model scale properties.There is NO Exception in runtime.I don't know WHY ,please help me,Thanks a lot!
public bool Update(Container model)
{
var mExist=dbContext.Container.SingleOrDefault(m=>m.TransportDocumentId==model.TransportDocumen tId && m.ContainerNo==model.ContainerNo);
if (mExist != null)
{
if (mExist.Id != model.Id)
{
throw new Exception("The same entity has been exist!.");
}
dbContext.Entry(mExist).State = EntityState.Detached;
}
var mOld = dbContext.Container.SingleOrDefault(m => m.Id == model.Id);
string oldContainerNo = model.ContainerNo;
if (mOld != null)
{
oldContainerNo = mOld.ContainerNo;
dbContext.Entry(mOld).State = EntityState.Detached;
}
dbContext.Container.Attach(model);
var mGoods = model.TransportDocument.Goods;
if (model.ContainerNo != oldContainerNo)
{
foreach (var g in mGoods)
{
var gn = g.GoodsContainerNo.Where(n => n.ContainerNo == oldContainerNo);
foreach (var gNo in gn)
{
//WHY,here CHANGES cannot be save to datastore!!!
gNo.ContainerNo = model.ContainerNo;
dbContext.Entry(gNo).State = EntityState.Modified;
}
}
}
dbContext.Entry(model).State = EntityState.Modified;
return dbContext.SaveChanges() >= 0;
}

In AS3/Flex, how can I get from flat data to hierarchical data?

I have some data that gets pulled out of a database and mapped to an arraycollection. This data has a field called parentid, and I would like to map the data into a new arraycollection with hierarchical information to then feed to an advanced data grid.
I think I'm basically trying to take the parent object, add a new property/field/variable of type ArrayCollection called children and then remove the child object from the original list and clone it into the children array? Any help would be greatly appreciated, and I apologize ahead of time for this code:
private function PutChildrenWithParents(accountData : ArrayCollection) : ArrayCollection{
var pos_inner:int = 0;
var pos_outer:int = 0;
while(pos_outer < accountData.length){
if (accountData[pos_outer].ParentId != null){
pos_inner = 0;
while(pos_inner < accountData.length){
if (accountData[pos_inner].Id == accountData[pos_outer].ParentId){
accountData.addItemAt(
accountData[pos_inner] + {children:new ArrayCollection(accountData[pos_outer])},
pos_inner
);
accountData.removeItemAt(pos_outer);
accountData.removeItemAt(pos_inner+1);
}
pos_inner++;
}
}
pos_outer++;
}
return accountData;
}
I had a similar problem with a hierarchical task set which was slightly different as it has many root elements, this is what i did, seems good to me:
public static function convertFlatTasks(tasks:Array):Array
{
var rootItems:Array = [];
var task:TaskData;
// hashify tasks on id and clear all pre existing children
var taskIdHash:Array = [];
for each (task in tasks){
taskIdHash[task.id] = task;
task.children = [];
task.originalChildren = [];
}
// loop through all tasks and push items into their parent
for each (task in tasks){
var parent:TaskData = taskIdHash[task.parentId];
// if no parent then root element, i.e push into the return Array
if (parent == null){
rootItems.push(task);
}
// if has parent push into children and originalChildren
else {
parent.children.push(task);
parent.originalChildren.push(task);
}
}
return rootItems;
}
Try this:
AccountData:
public class AccountData
{
public var Id:int;
public var ParentId:int;
public var children:/*AccountData*/Array;
public function AccountData(id:int, parentId:int)
{
children = [];
this.Id = id;
this.ParentId = parentId;
}
}
Code:
private function PutChildrenWithParents(accountData:ArrayCollection):AccountData
{
// dummy data for testing
//var arr:/*AccountData*/Array = [new AccountData(2, 1),
// new AccountData(1, 0), // root
// new AccountData(4, 2),
// new AccountData(3, 1)
// ];
var arr:/*AccountData*/Array = accountData.source;
var dict:Object = { };
var i:int;
// generate a lookup dictionary
for (i = 0; i < arr.length; i++)
{
dict[arr[i].Id] = arr[i];
}
// root element
dict[0] = new AccountData(0, 0);
// generate the tree
for (i = 0; i < arr.length; i++)
{
dict[arr[i].ParentId].children.push(arr[i]);
}
return dict[0];
}
dict[0] holds now your root element.
Maybe it's doesn't have the best possible performance but it does what you want.
PS: This code supposes that there are no invalid ParentId's.
Here's what I ended up doing, apparently you can dynamically add new properties to an object with
object['new_prop'] = whatever
From there, I used a recursive function to iterate through any children so you could have n levels of the hierarchy and if it found anything it would pass up through the chain by reference until the original function found it and acted on it.
private function PutChildrenWithParents(accountData : ArrayCollection) : ArrayCollection{
var pos_inner:int = 0;
var pos_outer:int = 0;
var result:Object = new Object();
while(pos_outer < accountData.length){
if (accountData[pos_outer].ParentId != null){
pos_inner = 0;
while(pos_inner < accountData.length){
result = CheckForParent(accountData[pos_inner],
accountData[pos_outer].ParentId);
if ( result != null ){
if(result.hasOwnProperty('children') == false){
result['children'] = new ArrayCollection();
}
result.children.addItem(accountData[pos_outer]);
accountData.removeItemAt(pos_outer);
pos_inner--;
}
pos_inner++;
}
}
pos_outer++;
}
return accountData;
}
private function CheckForParent(suspectedParent:Object, parentId:String) : Object{
var parentObj:Object;
var counter:int = 0;
if ( suspectedParent.hasOwnProperty('children') == true ){
while (counter < suspectedParent.children.length){
parentObj = CheckForParent(suspectedParent.children[counter], parentId);
if (parentObj != null){
return parentObj;
}
counter++;
}
}
if ( suspectedParent.Id == parentId ){
return suspectedParent;
}
return null;
}

Linq to DataSet - Handling Null Values

I have a requirement to convert LINQ to DataTable.
I stole the following Extension Method from StackOverflow:
public static DataTable ToDataTable<T>(this IEnumerable<T> items)
{
var tb = new DataTable(typeof(T).Name);
PropertyInfo[] props =
typeof(T).GetProperties(BindingFlags.Public
| BindingFlags.Instance);
foreach (var prop in props)
{
tb.Columns.Add(prop.Name, prop.PropertyType);
}
foreach (var item in items)
{
var values = new object[props.Length];
for (var i = 0; i < props.Length; i++)
{
values[i] = props[i].GetValue(item, null);
}
tb.Rows.Add(values);
}
return tb;
}
When the table contains null values it throws exception.
(i.e)
DataSet does not support System.Nullable<>
Comission (Decimal type) column contains null value)
at
tb.Columns.Add(prop.Name, prop.PropertyType);
How to fix it?
Here's a pimped version:
public static DataTable ToDataTable<T>(this IEnumerable<T> items) {
DataTable table = new DataTable(typeof(T).Name);
PropertyInfo[] props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var prop in props) {
Type propType = prop.PropertyType;
// Is it a nullable type? Get the underlying type
if (propType.IsGenericType && propType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
propType = new NullableConverter(propType).UnderlyingType;
table.Columns.Add(prop.Name, propType);
}
foreach (var item in items) {
var values = new object[props.Length];
for (var i = 0; i < props.Length; i++)
values[i] = props[i].GetValue(item, null);
table.Rows.Add(values);
}
return table;
}
Edit: Modified my code a bit, tested it, it works! :)
You could check for null, and then store DBNull.Value as the value instead. There is an MSDN article about null values, that specifically calls out the lack of support for Nullable<> by Datasets.
Where you have
values[i] = props[i].GetValue(item, null);
make it
var value = props[i].GetValue(item, null);
values[i] = value ?? ((object)DBNull.Value);

Resources