Flutter Firestore Query Field in Object - firebase

I'm writing a Flutter app and am trying to add documents to a list, where the contractorUserId value field (under jobBids) in Firestore is equal to the logged-in user. The image below shows the structure of my Firestore structure (contractorUserId in jobBids)
Firestore database
I'm using the following code:
_jobsCollectionReference.snapshots().listen((jobBidsSnapshot) {
if (jobBidsSnapshot.docs.isNotEmpty) {
var jobsWithBids = jobBidsSnapshot.docs
.map((jobBidsSnapshot) =>
JobWithBids.fromMap(jobBidsSnapshot.data(), jobBidsSnapshot.id))
.where((mappedItem) => mappedItem.jobBids != null)
.where((mappedItem) =>
mappedItem.jobBids
.map((e) => e.contractorUserId == loggedInUser.uid)
.toList()
.length >
0)
.toList();
This code results in a list with all objects where the contractorUserId field exists. However, the intention was to only add the documents where the contractorUserId is equal to the Logged in user.
Does anyone know what I'm doing wrong?

You're getting the error because the piece of code below evaluates to true since you're just checking the length of the list even if e.contractorUserId == loggedInUser.uid equals false :
mappedItem.jobBids
.map((e) => e.contractorUserId == loggedInUser.uid)
.toList()
.length >
0
So your code is actually:
var jobsWithBids = jobBidsSnapshot.docs
.map((jobBidsSnapshot) =>JobWithBids.fromMap(jobBidsSnapshot.data(), jobBidsSnapshot.id))
.where((mappedItem) => mappedItem.jobBids != null)
.where((mappedItem) => true) //This is what it evaluates to
.toList();
You should switch map to where in the last check, so it filters any list that does not satisfy the condition. See below:
var jobsWithBids = jobBidsSnapshot.docs
.map((jobBidsSnapshot) =>JobWithBids.fromMap(jobBidsSnapshot.data(), jobBidsSnapshot.id))
.where((mappedItem) => mappedItem.jobBids != null)
.where((mappedItem) => mappedItem.jobBids
.where((e) => e.contractorUserId == loggedInUser.uid)
.toList()
.length > 0
)
.toList();

Related

Lambda expression used inside Include is not valid when using where inside include

User user = await _context.users
.Include(u => u.orders.Where(o => o.Date > startDate && o.Date < enddate))
.Where(u => u.UserID == _auth.User.UserID)
.FirstOrDefaultAsync();
So I have one-to-many relationships between the Users and Orders table, where the user model has a List orders. But I get a 500 server error and "Lambda expression used inside Include is not valid"
I fixed the issue by downloading EF plus, and changing the query to
User user = await _context.users.IncludeFilter(u => u.orders.Where(o => o.Date > startDate && o.Date < enddate)).Where(u => u.UserID == _auth.User.UserID).FirstOrDefaultAsync();

How can i select distinct using one field

How can i select distinct() based on one field?
I have the following LINQ expression, how can I select distinct by ID field. for some reason i used .Distinct() but keeps shown me a duplicate, I want to show just one record
var customersbyName = await _context.vw_CustomerSearch.AsNoTracking()
.Where(c => c.Name.Contains(request.searchWord))
.Distinct()
.ToListAsync();
try:
var customersbyName = await _context.vw_CustomerSearch.AsNoTracking()
.Where(c => c.Name.Contains(request.searchWord))
.Select(c => c.ID)
.Distinct()
.ToListAsync();
Distinct compare each column of the row, so if one column is different, the row is distinct for linq / sql.
You can try it with a GroupBy:
var customersbyName = await _context.vw_CustomerSearch.AsNoTracking()
.Where(c => c.Name.Contains(request.searchWord))
.GroupBy(i => i.ID)
.Select(x => x.First())

How do i use onHourShow callback in a date_popup control with the Drupal Form API

I have a drupal form with a single date_popup field. I would like it to just provide the options of 12, 15 and 17 for the hours.
$form['order-group']['delivery'] = array(
'#title' => t('I Need The Equipment Ready By'),
'#type' => 'date_popup',
'#date_format' => 'd-M-Y H:i',
'#timepicker' => 'timepicker',
'#timepicker_options' => array(
'rows' => 3,
'hours' => array(
'starts' => 12,
'ends' => 17,
),
'onHourShow' => 'onHourShowCallback',
'minutes' => array(
'starts' => 0,
'ends' => 0,
),
'showCloseButton' => TRUE,
'closeButtonText' => t('Close'),
),
'#default_value' => date('Y-m-d 12:00',time()),
'#date_label_position' => '',
);
I then added the following to my javascript file (included with drupal_add_js, earlier in the script)
function onHourShowCallback(hour) {
return hour == 12 || hour == 15 || hour == 17;
};
However I get the following error:
Uncaught TypeError: onHourShow.apply is not a function
at Timepicker._generateHTMLHourCell (jquery.ui.timepicker.js?psw6eo:797)
at Timepicker._generateHTML (jquery.ui.timepicker.js?psw6eo:622)
at Timepicker._updateTimepicker (jquery.ui.timepicker.js?psw6eo:467)
at Timepicker._setTimeFromField (jquery.ui.timepicker.js?psw6eo:1112)
at Timepicker._attachTimepicker (jquery.ui.timepicker.js?psw6eo:190)
at HTMLInputElement.<anonymous> (jquery.ui.timepicker.js?psw6eo:1474)
at Function.each (jquery.min.js?v=1.7.2:2)
at $.fn.init.each (jquery.min.js?v=1.7.2:2)
at $.fn.init.$.fn.timepicker (jquery.ui.timepicker.js?psw6eo:1470)
at Object.attach (date_popup_timepicker.timepicker.js?psw6eo:8)
I tried asking this in the Drupal stack exchange but was put "On Hold" and told this is a programming question, so I am asking here instead.
jQuery UI Timepicker invokes callback functions such as 'beforeShow', 'onSelect', etc. using the method apply(), e.g. :
var beforeShow = $.timepicker._get(inst, 'beforeShow');
extendRemove(inst.settings, (beforeShow ? beforeShow.apply(input, [input, inst]) : {}));
Thus, the type of the callback must be a function - not a string.
The problem is that the module date_popup_timepicker does not map string callbacks (passed in from the server) to actual js function callbacks before initializing the timepicker, so once jquery.ui.timepicker.js code runs it throws an Uncaught TypeError: <callback>.apply is not a function.
On the client side, the datePopup settings object (from Drupal.settings) potentially contains string callbacks, so any of these strings must be converted to its corresponding function before calling the timepicker() method. What was missing to get there :
var timepicker_callbacks = {
beforeShow: null,
onSelect: null,
onClose: null,
onHourShow: null,
onMinuteShow: null
};
function timepicker_callbacks_assign (settings) {
for (var setting in settings) {
if (setting in timepicker_callbacks && typeof settings[setting] === 'string') {
var namespace = window,
ns_callback = settings[setting].split('.'),
func = ns_callback.pop();
for (var i = 0; i < ns_callback.length; i++) {
namespace = namespace[ns_callback[i]];
}
settings[setting] = namespace[func];
}
}
}
The timepicker() initialization occurs in Drupal.behaviors.DatePopupTimepicker, we just need to execute timepicker_callbacks_assign() first for the timepicker to get the proper settings.
I created an issue and submitted a patch on drupal.org, it still "Needs Review" so don't hesitate to apply from there and review it.

Linked list for firestore documents

I have a use case to make a linked list of documents like
{ name, next_ptr} and next_ptr is a reference to another document
I have following code and I am getting next_ptr but not getting fields belonging to next_ptr
I am getting following output
KkkGTTKjuwcGmzJzQ3Wa => FIRE => undefined
iW9lm7sYkgvuZPdVvrZE => GAS => undefined
NtTyJNjqIT79PZ6zkqtY => WATER => undefined
Expected Output
KkkGTTKjuwcGmzJzQ3Wa => FIRE => GAS
iW9lm7sYkgvuZPdVvrZE => GAS => WATER
NtTyJNjqIT79PZ6zkqtY => WATER => undefined
Code
db = defaultApp.firestore() ;
abc_collection = db.collection("abc") ;
abc_collection.get()
.then( data => {
data.forEach(item => {
console.log(item.id , "=>", item.get('name')) ;
next_ref = item.get('next_ptr') ;
next_ref.get("name").then(item => {
console.log(item) ;
}).catch("") ;
} ) ;
}).catch("") ;
It looks like you're assuming that the query results contain all the referenced documents:
item.get('next_ptr')['name']
What item.get('next_ptr') returns is a DocumentReference object, not the entire contents of the document. You will have to query that document with its get() method in order to load its contents, or find the document using its ID in the results that you queried (if you guarantee that the reference always points to a document in the same collection.
You might just be better off storing the string ID of the document if you don't want to deal with the DocumentReference.

Linq to objects giving strange error

I have the following code:
List<JobPortalInfo> jobPortalInfos = uow.JobPortalInfoRepository.GetQuery()
.Where(x => x.Job.Id == emailHash.JobId)
.ToList();
var temp = uow.EmailRepository.GetQuery()
.Where(x => jobPortalInfos.Any(y => (y.Contact != null && y.Contact.Id == x.ContactId)))
.ToList();
When I run the 2nd statement, I'm getting the error:
Unable to create a constant value of type 'CR.Data.JobPortalInfo'.
Only primitive types or enumeration types are supported in this context.
JobPortalInfo has a 1-[0 or 1] with Customer and Customer has a 1-* with Email.
Any ideas what I'm doing wrong here?
I figured it out.
jobPortalInfos is Linq to Objects, but EmailRepository is still an IQueryable/Linq To Entites. It doesn't know how to convert the LinqToObject jobPortalInfos to a Sql Server object.
I ended up doing this:
List<JobPortalInfo> jobPortalInfos = uow.JobPortalInfoRepository.GetQuery()
.Where(x => x.Job.Id == emailHash.JobId)
.ToList();
List<long> contactIds = jobPortalInfos
.Where(x => x.Contact != null)
.Select(y => y.Contact.Id)
.ToList();
var temp = uow.EmailRepository.GetQuery()
.Where(x => contactIds.Contains(x.ContactId))
.ToList();
Not sure if there is a more concise way to do this or not, but it seems to work.

Resources