I am working on a social network type site. I am wanting a way in which I can prompt users, get their response in an array, and then insert the array all at once. Whilst I can prompt I'm having trouble inserting the array into the mongodb database. Here is my code:
'click #creator': function(event){
var channelName = prompt('Enter The Channel Name');
var howmany = +prompt('How many people do you want? (max 10)');
var users = [];
var arr = []; // define our array
if(howmany > 1 && howmany<10){
for (var i = 0; i < howmany; i++) { // loop 10 times
arr.push(prompt('Enter a user' + (i+1))); // push the value into the array
}
users = arr.join('"," ');
Meteor.call('addChannel', channelName, users);
}
}
Inserting it in:
Channels = new Mongo.Collection('channels');
Meteor.methods({
addChannel: function(channelName, users){
if(!Meteor.userId()) {
throw new Meteor.Error('not-authorized', 'you are not signed in');
}
var username = Meteor.user().username;
Channels.insert({
name: channelName,
created: new Date(),
members: $push: {users}
createdBy: username
});
},
});
Since you are inserting and users is already an array you don't need to $push. Plus you don't need to push an {} object.
Channels.insert({
name: channelName,
created: new Date(),
members: users,
createdBy: username
});
Meanwhile on the client side, skip the arr.join() - that is creating a string but you just want to pass the array you created directly.
Meteor.call('addChannel', channelName, arr);
Related
I have a stripe function where I am trying to push the images into the array for each product. This is part of the prebuilt stripe checkout page... here's my function at whole:
//defining arrays
var productsArray = [];
var priceArray = [];
var imageArray = [];
//query to database
var productsStripe = "select * from " + tableID + "";
ibmdb.open(db2ConnString, function(err, conn) {
if (err) return console.log(err);
conn.query(productsStripe, async function (err, rows) {
if (err) {
console.log(err)
}
console.log(rows)
var itemName = ""
var itemPrice = ""
var totalNewPriceTest = ""
for(var i = 0; i < rows.length; i++)
//inserting items and prices into arrays
productsArray.push(rows[i]['NAME'])
priceArray.push(rows[i]['PRICE'])
imageArray.push(rows[i]['IMAGE_URL'])
}
//stripe
// loop over products array to construct the line_items
const items = productsArray.map((product, i) => {
return {
price_data: {
currency: 'CAD',
product_data: {
name: product,
images: imageArray[i]
},
unit_amount: parseInt(priceArray[i], 10) * 100,
},
quantity: 1,
};
});
its returning the error: (node:39728) UnhandledPromiseRejectionWarning: Error: Invalid array
how do I get the image array to populate the stripe page with images too? I pushed the values into the array, and am calling them , but not sure why it is returning invalid array. any ideas?
Observations
imageArray is array containing image urls for different products, one for each product in the productArray.
From the name of the prop images, the error message and the error line info provided by the OP, the prop images ought to be an array.
In the code, image: imageArray[i] means that the image prop is assigned a string but it should be array. So changing it with [imageArray[i]], we are assigning an array of length one to image prop containing image url for that product.
I have skills in one table, user_skills in other table and getting skills against id from skills table in for loop.I have stored query results in javascript array. I want a array with objects in it. I'm getting array in array structure. As you can see in image that i am getting multiple arrays in array.It should be objects in single array.
var userExist = await ctx.app.pool.query("SELECT * FROM USER_SKILLS WHERE user_id = $1",
[`${user_id}`]);
var strArray = userExist.rows[0].skill_array.split(",");
var i;
var skillsArray = [];
for (i = 0; i < strArray.length; i++) {
var findSkill = await ctx.app.pool.query("SELECT skill_name FROM ALL_SKILLS WHERE id = $1",
[`${strArray[i]}`]);
skillsArray.push(findSkill.rows);
}
console.log('skillsArray', skillsArray);
ctx.body = {
status: 200,
error: false,
message: "Skills found",
data: skillsArray
};
Assuming skill_array is in fact an array in postgres, you can combine both those queries into one:
const query = "SELECT skill_name
FROM ALL_SKILLS
WHERE id = ANY((
SELECT skill_array
FROM USER_SKILLS
WHERE user_id = $1
))";
const res = await ctx.app.pool.query(query, [`${user_id}`]);
That will be more performant than doing multiple queries.
Then the reason why you're getting an array with arrays is because skillsArray.push(findSkill.rows) puts the whole rows property, which is an array, into your skillsArray array.
It's not entirely clear to me exactly what is the format of the result you want, but I'll assume it's the actual skill names in an array, something like:
{
message: "Skills found",
data: [
"PHP",
"Node js"
]
}
In which case you could restructure your code to be something like this:
const query = "SELECT STRING_AGG(skill_name, ',') AS skill_names
FROM ALL_SKILLS
WHERE id = ANY((
SELECT skill_array
FROM USER_SKILLS
WHERE user_id = $1
))";
const res = await ctx.app.pool.query(query, [`${user_id}`]);
const skillNames = res.rows[0].skill_names.split(',');
ctx.body = {
status: 200,
error: false,
message: "Skills found",
data: skillNames
};
I've added a STRING_AGG because I like to get postgres results in a single row if possible rather than have pg read multiple rows sequentially, I believe it will be faster. I'm not using ARRAY_AGG because I don't know how the pg module treats arrays, whether it converts them to string or a js array. So I return one field with the skills concatenated with a comma, e.g. "PHP,Node js", then just need to split that one field by the comma to get the desired array.
I believe this is what you want
var userExist = await ctx.app.pool.query("SELECT * FROM USER_SKILLS WHERE user_id = $1",
[`${user_id}`]);
var strArray = userExist.rows[0].skill_array.split(",");
var i;
var skillsArray = [];
for (i = 0; i < strArray.length; i++) {
var findSkill = await ctx.app.pool.query("SELECT skill_name FROM ALL_SKILLS WHERE id = $1",
[`${strArray[i]}`]);
skillsArray.push(findSkill.rows[0]);
}
console.log('skillsArray', skillsArray);
ctx.body = {
status: 200,
error: false,
message: "Skills found",
data: skillsArray
};
But I as i mentioned in my comment, I suggest that you have your database tables/schema in relationships M:M, in your case, where you can just get the data you need in a single query, and it is considered bad practice to do a query in for(...) loop like this. you should use ORM like Sequelize or any other ORM that you prefer and works well with KOA, I hope this help you in achieving this:
I have pouchdb/couchbase data with equipment that has user assigned to them.
Equipment with _id and in the equipment doc there is a checkedOutBy with the user._id as the value. Within the employee object there is user.name. When I get the equipment objects how do I also get the user.name and display with the equipment.
I have searched and read about map/reduce that uses emit and do not grasp the idea. My code that i wrote from what i learned is:
by the way I am also using Angularjs.
field = "eq::"
this.getAllEquip = function(field){
function map(doc) {
if (doc.checkedOutBy !== undefined) {
emit(doc.checkedOutBy, {empName : doc.name});
}
}
var result = database.query(map, {include_docs: true,
attachments: true,
startkey: field,
endkey: field + '\uffff'})
.catch(function (err) {
//error stuff here
});
return result
};
I don't see where the two docs would get together. What am i missing? My result is empty.
The equipment json looks like:
{checkedOutBy: "us::10015", description: "3P Microsoft Surface w/stylus & power cord", equipId: "SUR1501", purchaseDate: "", rCost: 1000, id:"eq::10001"}
Emlpoyee json:
{"firstname":"Joe","gender":"male","lastname":"Blow","status":"active","title":"office","type":"userInfo","_id":"us::10015","_rev":"2-95e9f34784094104ad24bbf2894ae786"}
Thank you for your help.
Something like this should work, if I understood the question correctly:
//Sample Array of Objects with Equipment
var arr1=[{checkedout:"abc1",desc:"item1",id:1},
{checkedout:"abc2",desc:"item2",id:2},
{checkedout:"abc3",desc:"item3",id:3},
{checkedout:"abc1",desc:"item1",id:4},
{checkedout:"abc4",desc:"item3",id:5},
{checkedout:"abc6",desc:"item3",id:6}];
//Sample array of objects with Employee - the "id" in arr2 matches with "checkout" in arr1
var arr2=[{name:"john",id:"abc1"},
{name:"jack",id:"abc2"},
{name:"alice",id:"abc3"},
{name:"james",id:"abc4"}];
var result = []; //final result array
//loop through equipment array arr1
arr1.forEach(function(obj) {
var tempObj = obj;
var checkedout_id=obj.checkedout;
//do array.find which will return the first element in the array which satisfies the given function. This is absed on the assumption that that the id is unique for employee and there wont bwe multiple employees with same id (which is the "checkedout" field in equipment. If the employee is not found, it will return undefined.
var foundname = arr2.find(function(obj) {
if (obj.id == checkedout_id)
return obj.name
})
//Create the object to be inserted into the final array by adding a new key called "name", based on the result of above find function
if (foundname != undefined) {
tempObj.name=foundname.name
}
else {
tempObj.name = "Not found";
}
result.push(tempObj);
})
This is my Pouchdb solution, thank you Vijay for leading me to this solution.
First I get all my equipment. Then I use Vijay's idea to loop through the array and add the name to the object and build new array. I found there is a need to go into the .doc. part of the object as in obj.doc.checkedOutBy and tempObj.doc.name to get the job done.
$pouchDB.getAllDocs('eq::').then(function(udata){
var result = [];
//loop through equipment array
udata.rows.forEach(function(obj) {
var tempObj = obj;
var checkedout_id=obj.doc.checkedOutBy;
if (checkedout_id != undefined) {
$pouchDB.get(checkedout_id).then(function(emp){
return emp.firstname + " " + emp.lastname
}).then(function(name){
tempObj.doc.name = name;
});
}
result.push(tempObj);
})
in my service I have:
this.get = function(documentId) {
return database.get(documentId);
};
and:
this.getAllDocs = function(field){
return database.allDocs({
include_docs: true,
attachments: true,
startkey: field,
endkey: field + '\uffff'});
};
I'm attempting to add/remove entries from a Firebase database. I want to list them in a table to be added/modified/removed (front end) but I need a way to uniquely identify each entry in order to modify/remove. Firebase adds a unique identifier by default when using push(), but I didn't see anything referencing how to select this unique identifier in the API documentation. Can this even be done? Should I be using set() instead so I'm creating the unique ID?
I've put this quick example together using their tutorial:
<div id='messagesDiv'></div>
<input type='text' class="td-field" id='nameInput' placeholder='Name'>
<input type='text' class="td-field" id='messageInput' placeholder='Message'>
<input type='text' class="td-field" id='categoryInput' placeholder='Category'>
<input type='text' class="td-field" id='enabledInput' placeholder='Enabled'>
<input type='text' class="td-field" id='approvedInput' placeholder='Approved'>
<input type='Button' class="td-field" id='Submit' Value="Revove" onclick="msgRef.remove()">
<script>
var myDataRef = new Firebase('https://unique.firebase.com/');
$('.td-field').keypress(function (e) {
if (e.keyCode == 13) {
var name = $('#nameInput').val();
var text = $('#messageInput').val();
var category = $('#categoryInput').val();
var enabled = $('#enabledInput').val();
var approved = $('#approvedInput').val();
myDataRef.push({name: name, text: text, category: category, enabled: enabled, approved: approved });
$('#messageInput').val('');
}
});
myDataRef.on('child_added', function(snapshot) {
var message = snapshot.val();
displayChatMessage(message.name, message.text, message.category, message.enabled, message.approved);
});
function displayChatMessage(name, text, category, enabled, approved, ) {
$('<div/>').text(text).prepend($('<em/>').text(name+' : '+category +' : '+enabled +' : '+approved+ ' : ' )).appendTo($('#messagesDiv'));
$('#messagesDiv')[0].scrollTop = $('#messagesDiv')[0].scrollHeight;
};
</script>
Now lets assume I have three rows of data:
fred : 1 : 1 : 1 : test message 1
fred : 1 : 1 : 1 : test message 2
fred : 1 : 1 : 1 : test message 3
How do I go about uniquely identifying row 2?
in the Firebase Database they look like this:
-DatabaseName
-IuxeSuSiNy6xiahCXa0
approved: "1"
category: "1"
enabled: "1"
name: "Fred"
text: "test message 1"
-IuxeTjwWOhV0lyEP5hf
approved: "1"
category: "1"
enabled: "1"
name: "Fred"
text: "test message 2"
-IuxeUWgBMTH4Xk9QADM
approved: "1"
category: "1"
enabled: "1"
name: "Fred"
text: "test message 3"
To anybody finding this question & using Firebase 3+, the way you get auto generated object unique ids after push is by using the key property (not method) on the promise snapshot:
firebase
.ref('item')
.push({...})
.then((snap) => {
const key = snap.key
})
Read more about it in the Firebase docs.
As a side note, those that consider generating their own unique ID should think twice about it. It may have security and performance implications. If you're not sure about it, use Firebase's ID. It contains a timestamp and has some neat security features out of the box.
More about it here:
The unique key generated by push() are ordered by the current time, so the resulting list of items will be chronologically sorted. The keys are also designed to be unguessable (they contain 72 random bits of entropy).
To get the "name" of any snapshot (in this case, the ID created by push()) just call name() like this:
var name = snapshot.name();
If you want to get the name that has been auto-generated by push(), you can just call name() on the returned reference, like so:
var newRef = myDataRef.push(...);
var newID = newRef.name();
NOTE:
snapshot.name() has been deprecated. See other answers.
snapshot.name() has been deprecated. use key instead. The key property on any DataSnapshot (except for one which represents the root of a Firebase) will return the key name of the location that generated it. In your example:
myDataRef.on('child_added', function(snapshot) {
var message = snapshot.val();
var id = snapshot.key;
displayChatMessage(message.name, message.text, message.category, message.enabled, message.approved);
});
To get uniqueID after push() you must use this variant:
// Generate a reference to a new location and add some data using push()
var newPostRef = postsRef.push();
// Get the unique key generated by push()
var postId = newPostRef.key;
You generate a new Ref when you push() and using .key of this ref you can get uniqueID.
As #Rima pointed out, key() is the most straightforward way of getting the ID firebase assigned to your push().
If, however, you wish to cut-out the middle-man, Firebase released a gist with their ID generation code. It's simply a function of the current time, which is how they guarantee uniqueness, even w/o communicating w/ the server.
With that, you can use generateId(obj) and set(obj) to replicate the functionality of push()
Here's the ID function:
/**
* Fancy ID generator that creates 20-character string identifiers with the following properties:
*
* 1. They're based on timestamp so that they sort *after* any existing ids.
* 2. They contain 72-bits of random data after the timestamp so that IDs won't collide with other clients' IDs.
* 3. They sort *lexicographically* (so the timestamp is converted to characters that will sort properly).
* 4. They're monotonically increasing. Even if you generate more than one in the same timestamp, the
* latter ones will sort after the former ones. We do this by using the previous random bits
* but "incrementing" them by 1 (only in the case of a timestamp collision).
*/
generatePushID = (function() {
// Modeled after base64 web-safe chars, but ordered by ASCII.
var PUSH_CHARS = '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz';
// Timestamp of last push, used to prevent local collisions if you push twice in one ms.
var lastPushTime = 0;
// We generate 72-bits of randomness which get turned into 12 characters and appended to the
// timestamp to prevent collisions with other clients. We store the last characters we
// generated because in the event of a collision, we'll use those same characters except
// "incremented" by one.
var lastRandChars = [];
return function() {
var now = new Date().getTime();
var duplicateTime = (now === lastPushTime);
lastPushTime = now;
var timeStampChars = new Array(8);
for (var i = 7; i >= 0; i--) {
timeStampChars[i] = PUSH_CHARS.charAt(now % 64);
// NOTE: Can't use << here because javascript will convert to int and lose the upper bits.
now = Math.floor(now / 64);
}
if (now !== 0) throw new Error('We should have converted the entire timestamp.');
var id = timeStampChars.join('');
if (!duplicateTime) {
for (i = 0; i < 12; i++) {
lastRandChars[i] = Math.floor(Math.random() * 64);
}
} else {
// If the timestamp hasn't changed since last push, use the same random number, except incremented by 1.
for (i = 11; i >= 0 && lastRandChars[i] === 63; i--) {
lastRandChars[i] = 0;
}
lastRandChars[i]++;
}
for (i = 0; i < 12; i++) {
id += PUSH_CHARS.charAt(lastRandChars[i]);
}
if(id.length != 20) throw new Error('Length should be 20.');
return id;
};
})();
You can update record adding the ObjectID using a promise returned by .then() after the .push() with snapshot.key:
const ref = Firebase.database().ref(`/posts`);
ref.push({ title, categories, content, timestamp})
.then((snapshot) => {
ref.child(snapshot.key).update({"id": snapshot.key})
});
If you want to get the unique key generated by the firebase push() method while or after writing to the database without the need to make another call, here's how you do it:
var reference = firebaseDatabase.ref('your/reference').push()
var uniqueKey = reference.key
reference.set("helllooooo")
.then(() => {
console.log(uniqueKey)
// this uniqueKey will be the same key that was just add/saved to your database
// can check your local console and your database, you will see the same key in both firebase and your local console
})
.catch(err =>
console.log(err)
});
The push() method has a key property which provides the key that was just generated which you can use before, after, or while you write to the database.
Use push() to get a new reference and key to get the the unique id of the it.
var ref = FirebaseDatabase.instance.ref();
var newRef = ref.push(); // Get new key
print(newRef.key); // This is the new key i.e IqpDfbI8f7EXABCma1t
newRef.set({"Demo": "Data"}) // Will be set under the above key
How i did it like:
FirebaseDatabase mFirebaseDatabase = FirebaseDatabase.getInstance();
DatabaseReference ref = mFirebaseDatabase.getReference().child("users").child(uid);
String key = ref.push().getKey(); // this will fetch unique key in advance
ref.child(key).setValue(classObject);
Now you can retain key for further use..
I have tried following the tutorial at http://hacks.mozilla.org/2010/06/comparing-indexeddb-and-webdatabase/ with regards to doing queries in IndexedDB, but their example does not work.
How to I do a JOIN type query in IndexedDB? I have set my objectstores up with indexes, but I just cant seem to get the syntax?
IndexedDB is key-value (document) store. It doesn't have JOIN query or querying over multiple object store. However you can query multiple stores in a transaction. That is how suppose to make join query in IndexedDB.
I have a bit of writeup modeling relationship http://dev.yathit.com/ydn-db/schema.html using my library.
Here is joining query for SELECT * FROM Supplier, Part WHERE Supplier.CITY = Part.CITY.
var iter_supplier = new ydn.db.IndexValueIterator('Supplier', 'CITY');
var iter_part = new ydn.db.IndexValueIterator('Part', 'CITY');
var req = db.scan(function(keys, values) {
var SID = keys[0];
var PID = keys[1];
console.log(SID, PID);
if (!SID || !PID) {
return []; // done
}
var cmp = ydn.db.cmp(SID, PID); // compare keys
if (cmp == 0) {
console.log(values[0], values[1]);
return [true, true]; // advance both
} else if (cmp == 1) {
return [undefined, SID]; // jump PID cursor to match SID
} else {
return [PID, undefined]; // jump SID cursor to match PID
}
}, [iter_supplier, iter_part]);
See more detail on Join query article.