I have to fetch data at a couple of refs and update at a couple of refs. Everything works fine except for the fourth ref loopArrAtFourthRef that I have to update. It gets it's values from the third via a loop. The problem is the fifthRef finishes before the fourth ref. I'm a Swift dev and I can't get the hang of Promises, they are way to foreign for me.
exports.updateMultipleRefs = functions.https.onCall((data, context) => {
// ... values from data used in refs
const fetchFromFirstRef = admin.database()....
const updateAtSecondRef = admin.database()....
const runTransactionAtSecondRef = admin.database()....
const fetchArrDataFromThirdRef = admin.database()....
const loopArrAtFourthRef = admin.database()....
const updateFifthRef = admin.database()....
var arr = [];
var promises = [];
var val_1 = 0;
var val_2 = 0;
return fetchFromFirstRef
.once('value')
.then((snapshot) => {
if (snapshot.exists()) {
snapshot.forEach((childSnapshot) => {
// val_1 += data from each childSnapshot
});
return updateAtSecondRef.update({ "val_1":val_1 }).then(()=> {
return runTransactionAtSecondRef.set(admin.database.ServerValue.increment(1));
}).then(() => {
return fetchArrDataFromThirdRef
.once('value')
.then((snapshot) => {
if (snapshot.exists()) {
snapshot.forEach((childSnapshot) => {
var gameId = childSnapshot.key;
arr.push(gameId);
});
} else {
return null;
}
});
}).then(() => {
// this is where I'm having the problem, the fifth ref finishes before this does
for (var i = 0; i < arr.length; i++) {
var gameId = arr[i];
var promiseRef = loopArrAtFourthRef.child(gameId);
promises.push(promiseRef.once('value').then((snap) => {
snap.forEach((child) => {
// val_2 += data from each child
});
}));
return Promise.all(promises);
}
}).then(() => {
return updateFifthRef.update({ "val_2": val_2 });
});
} else {
return null;
}
})
.catch((error) => {
console.log('error', error);
return null;
});
});
Following this answer and this blog I just had to create an array of Promises and run Promise.all() after the outer for-loop finished:
for (var i = 0; i < arr.length; i++) {
var gameId = arr[i];
var promiseRef = loopArrAtFourthRef.child(gameId);
promises.push(promiseRef.once('value').then((snap) => {
snap.forEach((child) => {
// val_2 += data from each child
});
}));
}
return Promise.all(promises);
Related
Background:
I have a Parse database of images. Simply, my code does this:
A user, through a Parse Cloud call requests an image ("getNewPicture"). Nested within I check if he has seen any pictures before (alongside other requirements) and if so deliver one specific picture (getSpecifiedPicture). If he has not, then I deliver a new picture (getNewPicture).
Issue:
Calling "getNewPicture" through Parse Cloud Code function I get an error code 141. What's strange is that it works through Android but not iOS.
My code:
Parse.Cloud.define("getNewPicture", function(request, response) {
var SeenPictures = Parse.Object.extend("SeenPictures");
var query = new Parse.Query(SeenPictures);
var username = request.params.username;
var notWantedPics = [];
query.ascending("createdAt");
query.equalTo("username", username);
query.find({
success: function(results) {
for (var i = 0; i < results.length; i++) {
if (results[i].get("likes") == 1 || results[i].get("dislikes") == 1) {
notWantedPics.push(results[i].get("pictureId"));
results.splice(i, 1);
i--;
}
}
if (results != 0) {
getSpecifiedPicture(results[0].get("pictureId"), {
success: function(returnValue) {
response.success(returnValue);
},
error: function(error) {
response.error(error);
}
});
} else {
getNewPicture(username, notWantedPics, {
success: function(returnValue) {
response.success(returnValue);
},
error: function(error) {
response.error(error);
}
});
}
},
error: function() {
response.error(error);
}
});
});
function getSpecifiedPicture(specifiedPic, callback) {
var Pictures = Parse.Object.extend("Pictures");
var pictures = new Parse.Query(Pictures);
pictures.get(specifiedPic, {
success: function(picture) {
callback.success(picture);
},
error: function(error) {
callback.error(error);
}
});
}
function getNewPicture(username, notWantedPics, callback) {
var Pictures = Parse.Object.extend("Pictures");
var pictures = new Parse.Query(Pictures);
pictures.notEqualTo("photographerUserName", username);
pictures.notContainedIn("objectId", notWantedPics);
pictures.ascending("createdAt");
pictures.find({
success: function(results) {
if (results.length > 0) {
var object = results[0];
//Some other fancy stuff
object.save();
callback.success(object);
}
},
error: function(error) {
callback.error(error);
}
});
}
Why am I getting code 141? Any help is appreciated.
Thanks.
Your callbacks are a mess. I rewrote it to follow more of a promise chain style. Much easier to follow. Also, underscore.js is your friend. Hopefully I got your idea right.
var _ = require('underscore'); // Javascript Library
Parse.Cloud.define("getNewPicture", function(request, response) {
var username = request.params.username;
var notWantedPics = [];
if (!username) {
return response.error('No username.');
}
var query1 = new Parse.Query("SeenPictures");
query1.ascending("createdAt");
query1.equalTo("username", username);
var SeenPictures = query1.find();
return Parse.Promise.when([SeenPictures]).then(function (SeenPictures) {
SeenPictures = _.filter(SeenPictures, function (SeenPicture) {
if (SeenPicture.get("likes") == 1 || SeenPicture.get("dislikes") == 1) {
notWantedPics.push(SeenPicture.get("pictureId"));
return false;
}
else {
return true;
}
});
// notWantedPics?
if (SeenPictures > 0) {
var query2 = new Parse.Query("Pictures");
var Pictures = [query2.get(SeenPictures[0].get('pictureId'))];
}
else {
var query2 = new Parse.Query("Pictures");
query2.notEqualTo("photographerUserName", username);
query2.notContainedIn("objectId", notWantedPics);
query2.ascending("createdAt");
var Pictures = query2.find();
}
return Parse.Promise.when([Pictures]);
}).then(function (Pictures) {
if (Pictures > 0) {
// Success
return response.success(Pictures[0]);
} else {
return Parse.Promise.error("No pictures.");
}
}, function (error) {
// Error
return response.error(error);
});
});
I have a data content witch contains complex data I just need index names which seem in Dynamic View in data. In debug mode I can see the datas but cant get them..
You can see the contents of data in image below):
if(hits.Count() > 0)
{
var data = hits.FirstOrDefault().Source;
var dataaa = JsonConvert.DeserializeObject(hits.FirstOrDefault().Source);
}
I found a solution with checking if selected index has documents; if yes,
I take the first document in index, and parse it to keys(field names) in client.
here is my func:
[HttpPost]
public ActionResult getIndexFields(string index_name)
{
var node = new Uri("http://localhost:9200");
var settings = new ConnectionSettings(
node,
defaultIndex: index_name
);
var esclient = new ElasticClient(settings);
var Documents = esclient.Search<dynamic>(s => s.Index(index_name).AllTypes().Source());
string fields = "";
if (Documents.Documents.Count() > 0)
{
fields = JsonConvert.SerializeObject(Documents.Documents.FirstOrDefault());
var data = Documents.Documents.FirstOrDefault().Source;
return Json(new
{
result = fields,
Success = true
});
}
return Json(new
{
result = "",
Success = false
});
}
and my js:
$.ajax({
url: "getIndexFields?index_name=" + $(this).val(),
type: "POST",
success: function (data) {
if (data.Success) {
var fields = JSON.parse(data.result);
var fields_arr = [];
$.each(fields, function (value, index) {
fields_arr.push(
{
id: value,
label: value
})
});
options.filters = fields_arr;
var lang = "en";//$(this).val();
var done = function () {
var rules = $b.queryBuilder('getRules');
if (!$.isEmptyObject(rules)) {
options.rules = rules;
}
options.lang_code = lang;
$b.queryBuilder('destroy');
$('#builder').queryBuilder(options);
};
debugger
if ($.fn.queryBuilder.regional[lang] === undefined) {
$.getScript('../dist/i18n/query-builder.' + lang + '.js', done);
}
else {
done();
}
}
else {
event.theme = 'ruby';
event.heading = '<i class=\'fa fa-warning\'></i> Process Failure';
event.message = 'User could not create.';
event.sticky = true;
$("#divfailed").empty();
$("#divfailed").hide();
$("#divfailed").append("<i class='fa fa-warning'></i> " + data.ErrorMessage);
$("#divfailed").show(500);
setTimeout(function () {
$("#divfailed").hide(500);
}, 3000);
}
},
error: function (a, b, c) {
debugger
event.theme = 'ruby';
event.heading = '<i class=\'fa fa-warning\'></i> Process Failure';
event.message = 'Object could not create.';
$("#divfailed").empty();
$("#divfailed").hide();
msg = c !== "" ? c : a.responseText;
$("#divfailed").append("<i class='fa fa-warning'></i> " + msg);
$("#divfailed").show(500);
setTimeout(function () {
$("#divfailed").hide(500);
}, 3000);
}
});
I have a problem with saving data to storage.
I am using text fields and drop down menus.
Text field are working fine with saving but dropdown menu ain't working.
As you can see i am using local storage from html 5 to save everything
Does anyone know what the problem is ?
Woonplaats and favomuziek are with dropdown menu
$(document).ready(function(){
if (!window.localStorage){
function createCookie(name,value,days) {
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else var expires = "";
document.cookie = name+"="+value+expires+"; path=/";
}
function readCookie(name) {
var result = ""
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0){
result = c.substring(nameEQ.length,c.length);
}else{
result = "";
}
}
return(result);
}
localStorage = (function () {
return {
setItem: function (key, value) {
createCookie(key, value, 3000)
},
getItem: function (key) {
return(readCookie(key));
}
};
})();
}
load_settings();
$('#gebruikersprofiel').submit(function(event){
event.preventDefault();
save_settings();
});
});
function save_settings(){
localStorage.setItem("voornaam", $("#voornaam").val());
localStorage.setItem("achternaam", $("#achternaam").val());
localStorage.setItem("woonplaats", $("#woonplaats").val());
localStorage.setItem("favomuziek", $("#favomuziek").val());
apply_preferences_to_page();
}
function apply_preferences_to_page(){
$("body").css("voornaam", $("#voornaam").val());
$("body").css("achternaam", $("#achternaam").val());
$("body").css("woonplaats", $("#woonplaats").val() );
$("body").css("favomuziek", $("#favomuziek").val() );
}
$(document).ready(function(){
if (!window.localStorage){
function createCookie(name,value,days) {
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else var expires = "";
document.cookie = name+"="+value+expires+"; path=/";
}
function readCookie(name) {
var result = ""
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0){
result = c.substring(nameEQ.length,c.length);
}else{
result = "";
}
}
return(result);
}
localStorage = (function () {
return {
setItem: function (key, value) {
createCookie(key, value, 3000)
},
getItem: function (key) {
return(readCookie(key));
}
};
})();
}
load_settings();
$('#gebruikersprofiel').submit(function(event){
event.preventDefault();
save_settings();
});
});
function save_settings(){
localStorage.setItem("voornaam", $("#voornaam").val());
localStorage.setItem("achternaam", $("#achternaam").val());
localStorage.setItem("woonplaats", $("#woonplaats").val());
localStorage.setItem("favomuziek", $("#favomuziek").val());
apply_preferences_to_page();
}
function apply_preferences_to_page(){
$("body").css("voornaam", $("#voornaam").val());
$("body").css("achternaam", $("#achternaam").val());
$("body").css("woonplaats", $("#woonplaats").val() );
$("body").css("favomuziek", $("#favomuziek").val() );
}
my code is too long so sorry :)
#model IEnumerable<Osos11.Models.Customers>
#Html.DevExpress().GridView(
settings =>
{
settings.Name = "gvEditing";
settings.KeyFieldName = "sno";
settings.CallbackRouteValues = new { Controller = "Customer", Action = "EditingPartial" };
settings.Width = System.Web.UI.WebControls.Unit.Percentage(100);
settings.Columns.Add(column =>
{
column.Caption = "#";
column.SetDataItemTemplateContent(c =>
{
ViewContext.Writer.Write(
Html.ActionLink("Edit", "EditingEdit", new { sno = DataBinder.Eval(c.DataItem, "sno") }) + " " +
Html.ActionLink("Delete", "EditingDelete", new { sno = DataBinder.Eval(c.DataItem, "sno") },
new { onclick = "return confirm('Do you really want to delete this record?')" })
);
});
column.SetHeaderTemplateContent(c =>
{
ViewContext.Writer.Write(
Html.ActionLink("New", "EditingEdit", new { sno = -1 }).ToHtmlString()
);
});
column.Settings.AllowDragDrop = DefaultBoolean.False;
column.Settings.AllowSort = DefaultBoolean.False;
column.Width = 70;
});
settings.Columns.Add("Name");
//settings.Columns.Add(column =>
//{
// column.FieldName = "CategoryID";
// column.Caption = "Category";
// column.ColumnType = MVCxGridViewColumnType.ComboBox;
// var comboBoxProperties = column.PropertiesEdit as ComboBoxProperties;
// comboBoxProperties.DataSource = NorthwindDataProvider.GetCategories();
// comboBoxProperties.TextField = "CategoryName";
// comboBoxProperties.ValueField = "CategoryID";
// comboBoxProperties.ValueType = typeof(int);
//});
settings.Columns.Add("CustomerNumber");
//settings.Columns.Add("UnitPrice").PropertiesEdit.DisplayFormatString = "c";
//settings.Columns.Add("UnitsInStock");
//settings.Columns.Add("Discontinued", MVCxGridViewColumnType.CheckBox);
settings.ClientLayout = (s, e) =>
{
if (e.LayoutMode == ClientLayoutMode.Loading)
{
if (Session["GridState"] != null)
e.LayoutData = (string)Session["GridState"];
}
else
Session["GridState"] = e.LayoutData;
};
settings.PreRender = (s, e) =>
{
if (ViewData["VisibleID"] == null) return;
ASPxGridView grid = (ASPxGridView)s;
grid.MakeRowVisible(ViewData["VisibleID"]);
};
}).Bind(Model).GetHtml()
I got this error
Compiler Error Message: CS1660: Cannot convert lambda expression to type 'DevExpress.Web.Mvc.GridViewSettings' because it is not a delegate type
It seems that this issue is caused by the fact that any expression in the GridView's definition is not valid.
As a result, the entire GridView's definition (lambda expression) cannot be recognized by the View Engine.
I am making a private chatting application using private_pub, my question is how to unsubscribe from a channel using private_pub?
thanks for your help
if you are using pjax or ajax a lot in your site and the page you are loading with ajax you have private_pub subscribe method there you will find that It's subscribing many times
after searching a lot about that I found these fork from privat_pub javascript file which solved these problem
var PrivatePub = (function (doc) {
var self = {
connecting: false,
fayeClient: null,
fayeCallbacks: [],
subscriptions: {},
subscriptionCallbacks: {},
faye: function(callback) {
if (self.fayeClient) {
callback(self.fayeClient);
} else {
self.fayeCallbacks.push(callback);
if (self.subscriptions.server && !self.connecting) {
self.connecting = true;
if (typeof Faye === 'undefined') {
var script = doc.createElement("script");
script.type = "text/javascript";
script.src = self.subscriptions.server + ".js";
script.onload = self.connectToFaye;
doc.documentElement.appendChild(script);
} else {
self.connectToFaye();
}
}
}
},
connectToFaye: function() {
self.fayeClient = new Faye.Client(self.subscriptions.server);
self.fayeClient.addExtension(self.fayeExtension);
for (var i=0; i < self.fayeCallbacks.length; i++) {
self.fayeCallbacks[i](self.fayeClient);
};
},
fayeExtension: {
outgoing: function(message, callback) {
if (message.channel == "/meta/subscribe") {
// Attach the signature and timestamp to subscription messages
var subscription = self.subscriptions[message.subscription];
if (!message.ext) message.ext = {};
message.ext.private_pub_signature = subscription.signature;
message.ext.private_pub_timestamp = subscription.timestamp;
}
callback(message);
}
},
sign: function(options) {
if (!self.subscriptions.server) {
self.subscriptions.server = options.server;
}
if (!self.subscriptions[options.channel]) {
self.subscriptions[options.channel] = options;
self.faye(function(faye) {
faye.subscribe(options.channel, self.handleResponse);
});
}
},
handleResponse: function(message) {
if (message.eval) {
eval(message.eval);
}
if (callback = self.subscriptionCallbacks[message.channel]) {
callback(message.data, message.channel);
}
},
subscribe: function(channel, callback) {
self.subscriptionCallbacks[channel] = callback;
}
};
return self;
}(document));
try it.