Pouchdb join / link documents - javascript

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'});
};

Related

How do I get items from localStorage?

In my app I've got 2 functions to work with localStorage.
When I add the first and second items, it works properly, but when it is the third item, it gives an error.
Here are the functions:
w.getLocalStorage = function() {
var c = localStorage.getItem('cities');
var arr = [];
arr.push(c);
return c ? arr : [];
}
w.setLocalStorage = function(data, googleData, cities, name) {
if (data) {
city.name = data.name;
city.coord.lat = data.coord.lat;
city.coord.lon = data.coord.lon;
cities.push(JSON.stringify(city));
// console.log(city);
localStorage.setItem("cities", cities);
} else if (googleData) {
city.name = name;
city.coord.lat = googleData.results[0].geometry.location.lat;
city.coord.lon = googleData.results[0].geometry.location.lng;
console.log('cities', cities);
cities.push(JSON.stringify(city));
// console.log(cities, city);
localStorage.setItem("cities", cities);
}
}
Here is what it returns for the first 2 items:
Array[1]
0 : "{"name":"Pushcha-Voditsa","coord":{"lat":50.45,"lon":30.5}}"
1 : "{"name":"Kyiv","coord":{"lat":50.4501,"lon":30.5234}}"
Here is what when the third items is added:
Array[1]
0 : "{"name":"Pushcha-Voditsa","coord":{"lat":50.45,"lon":30.5}}, {"name":"Kyiv","coord":{"lat":50.4501,"lon":30.5234}}"
1 : "{"name":"Kyiv","coord":{"lat":50.4501,"lon":30.5234}}"
How can I fix this?
As you can only store string in localStorage, to persist object convert them in stringified format using JSON.stringify() method and on retrieval use JSON.parse() to parses the JSON string to construct the JavaScript value or object.
Here are the code snippet, which require attention. You should persist stringified cities data
cities.push(city);
localStorage.setItem("cities", JSON.stringify(cities));
While retrieval, parse it JavaScript object
var cities = localStorage.getItem('cities');
var c = cities ? JSON.parse(cities) || [];

How to get JSON Data depending on other data values in JavaScript

My Json is like this:
[
{"isoCode":"BW","name":"Botswana ","CashOut":"Y","BankOut":"","MMT":null},
{"isoCode":"BR","name":"Brazil ","CashOut":"Y","BankOut":"Y","MMT":null},
{"isoCode":"BG","name":"Bulgaria ","CashOut":"Y","BankOut":"Y","MMT":"Y"},
{"isoCode":"BF","name":"Burkina Faso","CashOut":"Y","BankOut":"","MMT":null},
{"isoCode":"BI","name":"Burundi","CashOut":"","BankOut":"","MMT":"Y"},
{"isoCode":"KH","name":"Cambodia","CashOut":"Y","BankOut":"","MMT":null}
]
I want all the names which have BankOut value as "Y" into an array using JavaScript, in order to use those names in my protractor automation.
You need to use filter method of array. It takes function as it argument. And runs it against each element of array. If function returns true (or other truthy value) then that element stays in newly created array.
var list =[ {"isoCode":"BW","name":"Botswana ","CashOut":"Y","BankOut":"","MMT":null},
{"isoCode":"BR","name":"Brazil ","CashOut":"Y","BankOut":"Y","MMT":null},
{"isoCode":"BG","name":"Bulgaria ","CashOut":"Y","BankOut":"Y","MMT":"Y"},
{"isoCode":"BF","name":"Burkina Faso ", "CashOut":"Y","BankOut":"","MMT":null},
{"isoCode":"BI","name":"Burundi","CashOut":"","BankOut":"","MMT":"Y"},
{"isoCode":"KH","name":"Cambodia","CashOut":"Y","BankOut":"","MMT":null}
];
var onlyBankOutY = list.filter(function (item) {
return item.BankOut === 'Y';
});
document.body.innerHTML = onlyBankOutY.map(function (item) {
return JSON.stringify(item);
}).join('<br>');
var list =[
{"isoCode":"BW","name":"Botswana ","CashOut":"Y","BankOut":"","MMT":null},
{"isoCode":"BR","name":"Brazil ","CashOut":"Y","BankOut":"Y","MMT":null},
{"isoCode":"BG","name":"Bulgaria ","CashOut":"Y","BankOut":"Y","MMT":"Y"},
{"isoCode":"BF","name":"Burkina Faso ", "CashOut":"Y","BankOut":"","MMT":null}, {"isoCode":"BI","name":"Burundi","CashOut":"","BankOut":"","MMT":"Y"},
{"isoCode":"KH","name":"Cambodia","CashOut":"Y","BankOut":"","MMT":null}
];
var names = [];
list.forEach(function(el) {
if (el.BankOut === 'Y') {
names.push(el.name)
}
})

javascript String to associative object

I am just wondering if there is an easy way to create an associative object from a string that needs double split, thisstring is the result from an api call, so length of the object could change.
For instance, if I have a string that looks like this:
var infoValue = 'Loan Date~Loan Number~Loan Amount|15/03/2016~1042~620|15/03/2016~1044~372';
I want to have an object that looks like this:
[
{
"Loan Date":"15/03/2016",
"Loan Number":"1042",
"Loan Amount":"620",
},
{
"Loan Date":"15/03/2016",
"Loan Number":"1042",
"Loan Amount":"620",
}
]
What I am doing right now is something like
var res = infoValue.split("|");
var activeLoans = new Array();
for(field in res) {
if(res[field] != ''){
activeLoans.push(res[field]);
}
}
for(field in activeLoans){
var row = activeLoans[field];
rowSplit = row.split("~");
}
But I am not happy with this approach, as I need to create a table to display this data, and the site that I am getting this api might change the order of the response of the string, or might add other values
What you have done is about all you can do, though I would not use for..in for a typical array. You should be able to deal with any sequence of values, as long as the header is consistent with the rest of the data, e.g.
var infoValue = 'Loan Date~Loan Number~Loan Amount|15/03/2016~1042~620|15/03/2016~1044~372';
function parseInfoValue(s) {
var b = s.split('|');
var header = b.shift().split('~');
return b.reduce(function(acc, data) {
var c = data.split('~');
var obj = {};
c.forEach(function(value, i){
obj[header[i]] = value;
})
acc.push(obj);
return acc;
},[]);
}
var x = parseInfoValue(infoValue);
document.write(JSON.stringify(x));
This will create the required structure no matter how many items are in each record, it just needs a label for each item in the header part and a value for each item (perhaps empty) in every data part.
Edit
Thinking on it a bit more, I don't know why I used forEach internally when reduce is the obvious candidate:
var infoValue = 'Loan Date~Loan Number~Loan Amount|15/03/2016~1042~620|15/03/2016~1044~372';
function parseInfoValue(s) {
var b = s.split('|');
var header = b.shift().split('~');
return b.reduce(function(acc, data) {
acc.push(data.split('~').reduce(function(obj, value, i) {
obj[header[i]] = value;
return obj;
}, {}));
return acc;
}, []);
}
var x = parseInfoValue(infoValue);
document.write(JSON.stringify(x));

JavaScript database correlation

I've been trying to 'correlate' between user picked answers and an object property name so that if the two matches then it will display what is inside.
My program is a recipe finder that gives back a recipe that consists of the ingredients the user picked.
my code currently looks like:
//property are the ingredients and the value are the recipes that contain those ingredients. The map is automatically generated
``var map = {
"pork" : [recipe1, recipe2, ...],
"beef" : [],
"chicken" :[],
}
//this gets the user pick from the dom
var cucumber = specificVegetable[7];
var lemon = specificFruits[0];
//Then this code finds the intersection of the recipe(recipes that use more than one ingredients)
function intersect(array1, array2)
{
return array1.filter(function(n) {
return array2.indexOf(n) != -1
});
}
var recipiesWithLemon = map["lemon"]; **// makes the lemon object is map**
var recipiesWithCucumber = map["cucumber"]; **// makes the cucumber object in map**
//Here is where I am stuck
function check(){
var both = intersect(recipiesWithLemon, recipiesWithCucumber);
if ( cucumber.checked && lemon.checked){
for (var stuff in map){
if(stuff="cucumber" && stuff="lemon"){
return both;
}
}
}
}
check();
so basically what I tried to do was I made my intersect and then if user pick is lemon and cucumber then look at the properties in the map object. if the name of the property equals to the exact string then return both. That was the plan but the code does not work and I'm not sure how to fix it.
My plan is to write code for every possible outcome the user may makes so I need to find the correlation between the user pick and the map which stores the recipe. I realize this is not the most effective way but I'm stumped on how to do it another way.
Thanks for the help.
Im using the open source project jinqJs to simplify the process.
I also changed your map to an array of JSON objects. If you must have the map object not as an array, let me know. I will change the sample code.
var map = [
{"pork" : ['recipe1', 'recipe2']},
{"beef" : ['recipe3', 'recipe4']},
{"peach" :['recipe5', 'recipe6']},
{"carrot" :['recipe7', 'recipe8']}
];
var selectedFruit = 'peach';
var selectedVeggie = 'carrot';
var selections = [selectedFruit, selectedVeggie];
var result = jinqJs().from(map).where(function(row){
for(var f in row) {
if (selections.indexOf(f) > -1)
return true;
}
return false;
}).select();
document.body.innerHTML += '<pre>' + JSON.stringify(result, null, 2) + '</pre><br><br>';
<script src="https://rawgit.com/fordth/jinqJs/master/jinqjs.js"></script>

Filter a backbone collection based on multiple model attributes

I am wanting to filter a backbone collection so returned to me are are only models that match or are close too some search parameters,
My models structure looks like this,
{
email: "name#domain.com",
first_name: "Name",
surname: "LastName",
handle: "NameLastName",
initials: "NL"
}
The model above is "User" model, it can be in the "UsersCollection", what I am hoping is achievable, is to search the "UsersCollection" for models based on the email address, first name, last name and handle, at the moment, I can only search based on one attribute, below is the search function from the "UsersCollection",
search : function(letters){
if(letters == "") return this;
var pattern = new RegExp(letters,"gi");
return _(this.filter(function(data) {
return pattern.test(data.get("first_name"));
}));
}
The letters parameter comes from the view, and they the value of a text input. Now this works, but it only creates matches based on the first_name, how could I match across multiple attributes?
now it will return the models that match either of the attribute.
var UsersCollection = Backbone.Collection.extend({
model: User,
myFilter: function( email, first_name, surname , handle) {
filtered = this.filter(function(user) {
return user.get("email") === email || user.get("first_name") === first_name ||
user.get("surname") === surname || user.get("handle") == handle ;
});
return new UsersCollection(filtered);
}
});
var filterdMe = UsersCollection.myFilter("ada#ff.d","something1","something2","something3");
I do something similar as well. I map an input attribute to a model key and pass an object to search that has the attributes the user is searching for. The search function is sort of like this: Here is a minimal jsbin demo.
var Collection = Backbone.Collection.extend({
model:yourModel,
search:function(find) {
return this.filter(function(model) {
var json = model.toJSON();
for (var k in find) {
var re = new RegExp(find[k],"i");
if (json[k].search(re) === -1) return false;
}
return true;
});
}
});
The html code looks like:
<input name="first_name"/>
<input name="last_name"/>
<input name="email"/>
The view code would be (more or less):
var View = Backbone.View.extend({
template:_.template($('#view-template').html()),
events: {
'keyup input' : 'search'
},
search:function() {
var find = {};
this.$('input').each(function() {
var $element = $(this),
modelKey = $element.attr('name'),
modelVal = $element.val();
find[modelKey] = modelVal;
});
var results = this.collection.search(find);
/* do something with results */
}
});
This seems to work decently if you don't have a large data-set. You could also use indexOf and toLowerCase if you didn't want to use a RegExp object. Maybe this will get you started down some path.
I know this is old. I solved the same thing today and thought I should post the code I'm using. I found a lot of this from another stackoverflow question. I can't find it now, sorry!
This will make a new array from a backbone collection. If you want another backbone collection you can do new BackboneCollection(search_results);.
var search_results = this.collection.filter(function(model) {
return _.some(model.attributes, function(val, attr) {
if(val !== null && val !== undefined)
{
if(!_.isString(val))
//if a model's attribute is a number, we make it a string.
{
val = val.toString();
}
//convert both options to uppercase for better searching ;)
val = val.toUpperCase();
q = q.toUpperCase(); //q is the search term, I grabbed it using JQuery
var array = q.split(" ");
return ~val.indexOf(q);
}
else
{
return false;
}
});
});
Note: This will not work for multiple words. If you were searching cars Volkswagen would work but not 1988 Volkswagen unless one of the model's attributes was "1988 Volkswagen" but they would more likely be two different attributes (year and make).

Categories

Resources