As i run a snapshot from a firebase database below it returns
Optional(498895446)
when i only want it to return
498895446
as an int. I have tried toint() but it is not working as i get an error. How can i get rid of this optional.
let ref = FIRDatabase.database().reference().child("Users + infomation").child(currentuser).child("timeStamp ")
ref.observeSingleEventOfType(.Value, withBlock : {(snapShot) in
let val = snapShot.value
if snapShot.exists(){
print("\(val)")
}
else if snapShot.exists() == false {
print("snappyaintexist")
}
})
Try:-
let ref = FIRDatabase.database().reference().child("Users + infomation").child(currentuser).child("timeStamp ")
ref.observeSingleEventOfType(.Value, withBlock : {(snapShot) in
if let val = snapShot.value as? Int{
print("\(val!)")
}else{
print("snappyaintexist")
}
})
Related
I'm writing a Flutter application which uses the user's location to identify items around them. As it's only possible to do comparison queries against one field in Firebase, I'm using geohashes as per Frank van Puffelen's lecture on the subject.
I've got the initial query working fine:
qs = await Firestore.instance
.collection('users')
.where('geohash', isGreaterThanOrEqualTo: boundaryGeoHash1)
.where('geohash', isLessThanOrEqualTo: boundaryGeoHash2)
.getDocuments();
this returns all the people in the required geographic area, as expected. The problem is, I expect there to be a high volume of users, so I want to limit the amount of downloads per query to a certain number - say 10.
When I write this query (which I believed should do the trick), what actually seems to happen is that the table is ordered by 'geohash', it then queries the first 10 items in the table, and then sends me the records in the first 10 items that fulfil the requirements of the .where part of the query:
qs = await Firestore.instance
.collection('users')
.orderBy('geohash')
.where('geohash', isGreaterThanOrEqualTo: boundaryGeoHash1)
.where('geohash', isLessThanOrEqualTo: boundaryGeoHash2)
.startAfterDocument(dS)
.limit(10)
.getDocuments();
//dS = last document from previous query
whereas what I want the query to do is to always send me 10 results, all of which fulfil the .where part of the query.
Using the test database I've generated, calling the initial query returns 114 results. The second one finds 2 which brings me to my conclusion as to what is happening.
Can what I'm trying to do be achieved? And if so, any clues as to what I'm doing wrong?
EDIT
As per Frank's request, dS is populated as follows:
if (qs != null) {
dS = qs.documents[qs.documents.length - 1];
}
//dS is a global variable
EDIT 2
Here is the function which does the query on the database.
Future<List<CutDownUserProfile>> getReducedUserDataBetweenGeohashes(
String boundaryGeoHash1, String boundaryGeoHash2, DocumentSnapshot dS, int downloadLimit) async {
List<CutDownUserProfile> retn = List<CutDownUserProfile>();
QuerySnapshot qs;
if (dS != null) {
print('ds != null');
print('dS.userNumber = ' + dS.data['userNumber'].toString());
print('dS.userID = ' + dS.data['userID']);
print('dS.geohash = ' + dS.data['geohash']);
print('dS.name = ' + dS.data['name']);
qs = await Firestore.instance
.collection('userHeaders')
.orderBy('geohash')
.where('geohash', isGreaterThanOrEqualTo: boundaryGeoHash1)
.where('geohash', isLessThanOrEqualTo: boundaryGeoHash2)
.startAfterDocument(dS)
.limit(downloadLimit)
.getDocuments();
} else {
print('ds == null');
qs = await Firestore.instance
.collection('userHeaders')
.orderBy('geohash')
.where('geohash', isGreaterThanOrEqualTo: boundaryGeoHash1)
.where('geohash', isLessThanOrEqualTo: boundaryGeoHash2)
.limit(downloadLimit)
.getDocuments();
}
if (qs.documents.isNotEmpty) {
print('through this! qs len = ' + qs.documents.length.toString());
List<DocumentSnapshot> ds = qs.documents.toList();
print('/////DS Len = ' + ds.length.toString());
for (int i = 0; i < ds.length; i++) {
CutDownUserProfile cDUP = CutDownUserProfile();
cDUP.geoHash = ds[i].data['geohash'];
Vector2 latLon = globals.decodeGeohash(cDUP.geoHash);
double dist = getDistanceFromLatLonInKm(globals.localUser.homeLat, globals.localUser.homeLon, latLon.x, latLon.y);
if (dist <= globals.localUser.maxDistance && dist <= ds[i].data['maxDist']) {
CutDownUserProfile cDUP2 = CutDownUserProfile();
cDUP2.userNumber = ds[i].data['userNumber'];
cDUP2.userID = ds[i].data['userID'];
cDUP2.geoHash = ds[i].data['geohash'];
retn.add(cDUP2);
}
}
if (qs != null) {
globals.lastProfileSeen = qs.documents[qs.documents.length - 1];
}
} else {
print('no results');
}
}
The line print('/////DS Len = ' + ds.length.toString()); prints out the length of the queries returned from the search, and, as mentioned earlier returns 2. Without the .orderBy the .startAfterDocument(dS) and the .limit(downloadLimit) the code returns 114 results, which is what I expected. For completeness, here is the original code:
Future<List<CutDownUserProfile>> getReducedUserDataBetweenGeohashesALL(String boundaryGeoHash1, String boundaryGeoHash2) async {
List<CutDownUserProfile> retn = List<CutDownUserProfile>();
await Firestore.instance
.collection('userHeaders')
.where('geohash', isGreaterThanOrEqualTo: boundaryGeoHash1)
.where('geohash', isLessThanOrEqualTo: boundaryGeoHash2)
.getDocuments()
.then((event) {
if (event.documents.isNotEmpty) {
List<DocumentSnapshot> ds = event.documents.toList(); //if it is a single document
print('/////DS Len = ' + ds.length.toString());
for (int i = 0; i < ds.length; i++) {
CutDownUserProfile cDUP = CutDownUserProfile();
cDUP.geoHash = ds[i].data['geohash'];
Vector2 latLon = globals.decodeGeohash(cDUP.geoHash);
double dist = getDistanceFromLatLonInKm(globals.localUser.homeLat, globals.localUser.homeLon, latLon.x, latLon.y);
CutDownUserProfile cDUP2 = CutDownUserProfile();
cDUP2.userNumber = ds[i].data['userNumber'];
cDUP2.userID = ds[i].data['userID'];
cDUP2.geoHash = ds[i].data['geohash'];
retn.add(cDUP2);
}
} else {
print('no results');
}
}).catchError((e) => print("error fetching data: $e"));
I have this piece of code like this:
var options = new DynamoDBOperationConfig
{
ConditionalOperator = ConditionalOperatorValues.Or,
OverrideTableName = nameTable,
ConsistentRead = true
};
new QueryOperationConfig()
{
IndexName = indexName,
Filter = queryFilter,
Select = SelectValues.Count
};
result = context.FromQueryAsync<TEntity>(queryConfig, options).GetRemainingAsync().Result;
as per the documentation, it should return just the count of values that match the filter, at least, the piece of code in the SelectValues class says that
//
// Summary:
// An enumeration of all supported Select values for Query and Scan. Value of Count
// will force service to return the number of items, not the items themselves.
but result is always an empty list; how can i make the count work ?
If you are still looking for the answer, this is the solution:
new QueryOperationConfig()
{
IndexName = indexName,
Filter = queryFilter,
Select = SelectValues.Count,
ConsistentRead = true
};
var table = context.GetTargetTable<TEntity>();
var search = table.Query(queryConfig);
result = search.Count;
Having ConsistentRead set to true will cause it to give you real time updates when the table is updated.
It's not working on Document level...
You can try to do this in low level model.
int count = 0;
Dictionary<string, AttributeValue> lastKey = null;
do
{
var request = new QueryRequest
{
TableName = "tableNmae",
IndexName = "indexName",
KeyConditionExpression = "ID= :v_ID",
ExpressionAttributeValues = new Dictionary<string, AttributeValue>
{
{
":v_ID",
new AttributeValue
{
N = "1"
}
}
},
ConsistentRead = false,
Select = Select.COUNT,
ExclusiveStartKey = lastKey
};
var respone = await tableClient.QueryAsync(request);
count += respone.Count;
lastKey = respone.LastEvaluatedKey;
} while (lastKey != null && lastKey.Count != 0);
I trying to write an encryption (AESCBC128) function based on CCCrypt and the CCCrypt is generating a random value.
for example, when I pass 016768821221 to function it'll return "0oTPFcKNWABTpBGgLlzsjw==" for the same iv and Key.
here's the iv: "khabbababab" and the key is : "khabbababab"
why it returns nil. The encryption is correct but some times it returns nil
extension String {
func aesEncrypt(key:String, iv:String, options:Int = kCCOptionPKCS7Padding) -> String? {
if let keyData = key.data(using: String.Encoding.utf8),
let data = self.data(using: String.Encoding.utf8),
let cryptData = NSMutableData(length: Int((data.count)) + kCCBlockSizeAES128) {
let keyLength = kCCKeySizeAES128
let operation: CCOperation = UInt32(kCCEncrypt)
let algoritm: CCAlgorithm = CCOptions(kCCAlgorithmAES128)
let options: CCOptions = UInt32(options)
var numBytesEncrypted :size_t = 0
let cryptStatus = CCCrypt(operation,
algoritm,
CCOptions(options),
(keyData as NSData).bytes, keyLength,
iv,
(data as NSData).bytes, data.count,
cryptData.mutableBytes, cryptData.length,
&numBytesEncrypted)
print(String(data: data, encoding: .utf8) as Any)
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
cryptData.length = Int(numBytesEncrypted)
let base64cryptString = cryptData.base64EncodedString(options: .lineLength64Characters)
print("succccc")
return base64cryptString
}
else {
print("nill nill llllllllll")
return nil
}
}
return nil
}
func aesDecrypt(key:String, iv:String, options:Int = kCCOptionPKCS7Padding) -> String? {
if let keyData = key.data(using: String.Encoding.utf8),
let data = NSData(base64Encoded: self, options: .ignoreUnknownCharacters),
let cryptData = NSMutableData(length: Int((data.length)) + kCCBlockSizeAES128) {
let keyLength = size_t(kCCKeySizeAES128)
let operation: CCOperation = UInt32(kCCDecrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options: CCOptions = UInt32(options)
var numBytesEncrypted :size_t = 0
let cryptStatus = CCCrypt(operation,
algoritm,
options,
(keyData as NSData).bytes, keyLength,
iv,
data.bytes, data.length,
cryptData.mutableBytes, cryptData.length,
&numBytesEncrypted)
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
cryptData.length = Int(numBytesEncrypted)
let unencryptedMessage = String(data: cryptData as Data, encoding:String.Encoding.utf8)
return unencryptedMessage
}
else {
return nil
}
}
return nil
}
Your aesEncrypt always passes a keylength of 16 to CCCrypt without checking that the key actually has at least 16 bytes of data.
I have a mutableAttributedString in which few strings are linkAttributed,I want to find the Range of all link attributed string. How to do that in swift3 ?
When user start type # in textview i show list of few name. If user select any row then following method gets called.
func didSelectMemberId(_ model: BaseModel) {
var fullName = ""
if model.entityType == ReceiverType.Active.rawValue{
fullName = model.name
}else{
fullName = AtMention + model.name + " " + model.name2
}
let attributedString = NSMutableAttributedString(string:fullName, attributes:[NSFontAttributeName:(appNeedsAutoResize ? (UIUtils.getFontForApproprieteField(.headlineWithoutBold).font) : UIFont.systemFont(ofSize: 14))])
attributedString.addAttribute(NSLinkAttributeName, value: "connectmention://\(model.entityId.stringValue())", range: NSRange(location: 0, length: fullName.length))
attributedString.append(NSAttributedString(string: emptySpaceStringByUC, attributes:[NSFontAttributeName:(appNeedsAutoResize ? (UIUtils.getFontForApproprieteField(.headlineWithoutBold).font) : UIFont.systemFont(ofSize: 14))]))
self.composeBar.textView.textStorage.insert(attributedString, at:self.composeBar.textView.selectedRange.location)
}
self.composeBar.textView.selectedRange = NSMakeRange(self.composeBar.textView.selectedRange.location+fullName.length, 0 )
To get the link proprty I am using the following method
func getlinkActionRange(attributeString: NSAttributedString) -> [MentionStruct] {
var arrMentions = [MentionStruct]()
_ = attributeString.enumerateAttribute(NSLinkAttributeName, in: NSRange.init(location: 0, length: attributeString.length), options: [], using: { (value, range, stop) in
if let url = value {
let occurrence = (attributeString.string as NSString).substring(with:range)
arrMentions.append(MentionStruct(link: url as! String, text: occurrence, range: range))
}
})
return arrMentions
}
If user type anything after inserting that name , that type string also coming.
I am trying some async ops in f# but w/o much luck. I am trying to grab records from the db and perform operations on each record in Parallel.
let IsA1 companyId =
query { for comp in db.Company do
join cc in db.CC on (comp.CompanyId = int(cc.CompanyId))
join pp in db.PP on (cc.PartId = pp.PartId)
join tl in db.TL on (pp.CompanyId = tl.CompanyId)
where (comp.CompanyId = companyId)
select (comp.CompanyId > 0)
}
|> Seq.length |> fun len -> len > 0
let IsA2 companyId =
query { for t in db.Title do
join pp in db.PP on (t.Tid = pp.Tid)
join comp in db.Company on (pp.CompanyId = comp.CompanyId)
where (comp.CompanyId = companyId)
select (comp.CompanyId > 0)
}
|> Seq.length |> fun len -> len > 0
let GetAffiliations id =
async {
if (IsA1 id) then return "AffilBBB"
elif (IsA2 id) then return "AffilCCD"
else return Unknown
}
let ProcessCompany (company:dbSchema.ServiceTypes.Company) =
async {
let grp = GetAffiliations company.CompanyId
let result = { Id=company.CompanyId; Name=company.Name; Affiliations=grp; ContactType="ok"; }
return result
}
let GetCompanyNames =
let companies = db.Company |> Seq.distinctBy(fun d -> d.CompanyId)
companies
|> Seq.map(fun co -> ProcessCompany co)
|> Async.Parallel
|> Async.RunSynchronously
When I run the above code, I get error:
System.ArgumentException: An item with the same key has already been added.
The error is occurring as a result of another function call inside async { }:
let grp = GetAffiliations company.CompanyId
I am sure its a newbie issue, but I am not sure what the issue is. I even tried making the call inside of the async{ } another async call and used let! grp = (GetAffiliations company.CompanyId) but that does not resolve.
Because the two concurrent queries are sharing the same context, when the second result is added to the same context, you get an error saying that the context already has an item with the same key.
Using distinct instances of the 'db' context for each of the queries, should solve your issue.