Search in columns, grid in extjs4 - search

I'm trying to build a search for the grids i just made. I tried LiveSearchGridPanel but it's too slow and buggy. So I'm trying to build a different search I do have in some old examples of grids in the application I'm working with. The code below is taken from the example i have, it uses:
fieldlabel:'Search',
puts the search inside a tbar and filters the results of the research by columns.
// search
{
xtype : 'combo',
enableKeyEvents : true,
fieldLabel : 'Search',
hideTrigger : true,
typeAhead : false,
editable : true,
listeners : {
'specialkey' : function(field, e) {
// pressing enter
if (e.keyCode == 13) {
if (field.lastValue != null|| field.lastValue != undefined) {
// if the search key isn't empty
var search = field.lastValue;
// remove old filter
if (store.isFiltered())
store.clearFilter(true);
// apply filter on fields selected
if (checked[0] == 1) {
if (checked[1] == 1)
if (checked[2] == 1)
store.filter([{
property : "admantN",
value : search,
anyMatch : true
}],
[{
property : "admant",
value : search,
anyMatch : true
}],
[{
property : "userN",
value : search,
anyMatch : true
}]);
else
store.filter([{
property : "admantN",
value : search,
anyMatch : true
}],
[{
property : "admant",
value : search,
anyMatch : true
}]);
else {
if (checked[2] == 1)
store.filter([{
property : "admantN",
value : search,
anyMatch : true
}],
[{
property : "userN",
value : search,
anyMatch : true
}]);
else
store.filter([{
property : "admantN",
value : search,
anyMatch : true
}]);
}
}
else {
if (checked[1] == 1)
if (checked[2] == 1)
store.filter([{
property : "userN",
value : search,
anyMatch : true
}],[{
property : "admant",
value : search,
anyMatch : true
}]);
else
store.filter([{
property : "admant",
value : search,
anyMatch : true
}]);
else
if (checked[2] == 1)
store.filter([{
property : "userN",
value : search,
anyMatch : true
}]);
}
search = "";
}
else {// if search key is blank remove old filters
if (store.isFiltered()) {
store.clearFilter();
}
}}}}// end listeners
},
// to select in which field search
{
xtype : 'checkboxgroup',
store : checked,
columns : 3,
vertical : false,
width : 250,
items : [
{
// Default searching field
boxLabel : 'Name',
checked : true
},
{boxLabel : 'Admant'},
{boxLabel : 'Username'}
],
listeners :
{
'change' :
// store checked field
function(th, newValue, oldValue) {
var ics = th.items.items;
for (i = 0; i < 3; i++) {
checked[i] = ics[i].checked;
}
}
}
},
// Refresh button
{
xtype : 'button',
text : 'Refresh',
icon : 'images/refresh.gif',
handler :
function() {
metodoA = "list";
// remove pending filters
if (store.isFiltered())
store.clearFilter(true);
// refresh data from the server
Ext.Ajax.request({
method : "GET",
url : ur + "admants?MetodoAD="+ metodoA + "&DBad=" + dbA,
timeout : 10000,
success :
function(response) {
var obj = null;
try {
obj = Ext.decode(response.responseText);
}
catch (error) {}
if (obj) {
store.loadData(obj);
}
else {
console.log('Invalid response');
}
},
failure :
function(response) {
alert("Refreshing request failed");
}
});}}]
// end toolbar's item
},// end tbar
The only problem copying this solution is that i cannot find any tutorial or manual that uses fieldlabel and tbar search to define a search box which will work only after i press the enter button and which is not a "live search".
Anyone has any hints?

The trick is simple, to create a search without the livesearchgridpanel you have to create an item in the table, which is called 'combo':
xtype: 'combo',
In the code pasted in the question you will have to change the value of the "store" keyword to mach with the keyword of your own store. This is used to retrieve the data to be shown after the research is made.It is done by the filter method of the store option.
After that you have to set the parameters of the filter function to mach the parameters in your store. The use the "checked" store to decide on which basis to operate your search. There is an array of three parameters in your example.
Place the whole code inside the "ext.grid.Panel" call.

Related

complicated mongoose pull list of data from api and insert into mongodb if it doesn't already exist

I am connecting to the Yelp API using the RapidAPI module in Nodejs. I am able to request a token, connect, and request data, retrieve that data, and insert the relevant information for each result it into mongodb. Here's where it gets complicated...
Let's say I make a Yelp API request and search for bars. I get a list of bars and insert them into the database. Let's say one of these in the list is "Joe's Bar & Grill". One of the fields in my mongodb is "type" and it's an array. So now, this particular document will look something like this:
{
id: 'joes-bar-and-grill',
name: 'Joe\'s Bar & Grill',
type: ['bar']
}
But then I run another request on the Yelp API on "restaurants", and in this list "Joe's Bar & Grill" shows up again. Instead of inserting a new duplicate document into mongodb, I'd like the existing document to end up looking like this:
{
id: 'joes-bar-and-grill',
name: 'Joe\'s Bar & Grill',
type: ['bar', 'restaurant']
}
In addition to this, let's say I run another request again for "bars", and "Joe's Bar & Grill" comes up again. I don't want it to automatically insert "bar" into the type array again, if "bar" already exists in its array.
I've tried findOneAndUpdate with upsert: true and a $push of new data into the array, but I cannot get it to work at all. Does anyone have any ideas?
You can use findOneAndUpdate, combined with $addToSet (to make sure that an entry in the array only exists once) and $each (to allow passing arrays to $addToSet):
Bar.findOneAndUpdate({ id : 'joes-bar-and-grill' }, {
id : 'joes-bar-and-grill',
name : 'Joe\'s Bar & Grill',
$addToSet : { type : { $each : [ 'restaurant' ] } }
}, { upsert : true })
EDIT: now that you posted your entire code, the problem becomes more obvious.
For one, I'm not sure if the third and fourth arguments that you're passing to Location.update() make sense. As far as I know, the third should be an option object, and the fourth an async function.
Secondly, it looks like you're just ignoring any update errors.
And lastly, this isn't going to work:
for (var i = 0; i < payload.businesses.length; i++) { Location.update(...) }
Because Location.update() is asynchronous, the i variable will get clobbered (you should browse around on SO to find the explanation for that; for example, see this question).
You're going to need a library that will provide you with better async support, and preferably one that will also help limiting the number of update queries.
Once such library is async, and using it, your code would become something like this:
const async = require('async');
...
async.eachLimit(payload.businesses, 5, function(business, callback) {
Location.update({ yelpID : business.id }, {
name : business.name,
latitude : business.location.latitude,
longitude : business.location.longitude,
address1 : business.location.address1,
address2 : business.location.address2,
address3 : business.location.address3,
city : business.location.city,
state : business.location.state,
zip_code : business.location.zip_code,
country : business.location.country,
timezone : 'CST'
$addToSet : { type : 'bar' }
}, { upsert : true }, callback);
}, function(err) {
if (err) {
console.error(err);
} else {
console.log('All documents inserted');
}
});
You may use $addToSet operator
The $addToSet operator adds a value to an array unless the value is
already present, in which case $addToSet does nothing to that array.
$addToSet only ensures that there are no duplicate items added to the
set and does not affect existing duplicate elements. $addToSet does
not guarantee a particular ordering of elements in the modified set.
If the field is absent in the document to update, $addToSet creates
the array field with the specified value as its element.
If the field is not an array, the operation will fail.
The below solution assumes that on each update, you receive a single type and not an array. If the input document is an array itself, you may use robertklep's solution with $each operator
db.mycoll.update(
{ "id" : "joes-bar-and-grill" },
{
$set:{
name : 'Joe\'s Bar & Grill',
},
$addToSet : { type : 'restaurant' }
},
true, false);
I have also used $set operator.
The $set operator replaces the value of a field with the specified
value.
The $set operator expression has the following form:
{ $set: { field1: value1, ... } }
Here is the mongo shell output to explain it further :
> db.mycoll.find({ "id" : "joes-bar-and-grill" });
// NO RESULT
> db.mycoll.update(
... { "id" : "joes-bar-and-grill" },
... {
... $set:{
... name : 'Joe\'s Bar & Grill',
... },
... $addToSet : { type : 'restaurant' }
... },
... true, false);
WriteResult({
"nMatched" : 0,
"nUpserted" : 1,
"nModified" : 0,
"_id" : ObjectId("58e719b4d543c5e30d615d59")
})
// INSERTED A NEW DOCUMENT AS IT DOES NOT EXIST
> db.mycoll.find({ "id" : "joes-bar-and-grill" }); // FINDING THE OBJECT
{ "_id" : ObjectId("58e719b4d543c5e30d615d59"), "id" : "joes-bar-and-grill", "name" : "Joe's Bar & Grill", "type" : [ "restaurant" ] }
> db.mycoll.update(
... { "id" : "joes-bar-and-grill" },
... {
... $set:{
... name : 'Joe\'s Bar & Grill',
... },
... $addToSet : { type : 'bar' }
... },
... true, false);
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
// UPDATING THE DOCUMENT WITH NEW TYPE : "bar"
> db.mycoll.findOne({ "id" : "joes-bar-and-grill" });
{
"_id" : ObjectId("58e719b4d543c5e30d615d59"),
"id" : "joes-bar-and-grill",
"name" : "Joe's Bar & Grill",
"type" : [
"restaurant",
"bar"
]
}

Sort descending String with Number in Mongo DB

I have currently a DB with two fields. Only one of them matter for the purpose of this question.
Imagine a DB with a single String field (let's call it "Tags"), and the following pattern: [a-z]*[0-9]*, like:
test129
test130
some43
some44
some45
...
My application needs to generate new "Tags", given the prepend "identifier" (like test or some).
So let's say I input test as the prepend name, and 100 as the number of "Tags" to generate.
He finds the LAST tag with the prepended name test on it.
Parses the number after the prepended name.
Sum +1 on that number, and generate 100 tags with the sequence.
Output in this specific case, would be: test131, test132, ..., test230.
I implemented this, and it was working just great with Mongoose. However, when I tried to generate a "Tag" from a already existent Tag with more than 1000, I found that the first step was a flaw. It was returning, let's say test999 instead of test1200, and causing the iteration to start from 999, and getting errors since it needs to be unique.
This is because, sorting a String differs from sorting a Number. I know the problem, but how can I solve this in a simple way, without having to create extra fields?
UPDATE: Part of the code where I find the tag:
lastAliasNumber: function (next){
console.log('process.lastAliasNumber');
// Skip if prefix is not set (tags already have name)
if(!prefix) return next();
// Build RegExp to find tags with the prefix given
var regexp = new RegExp('^'+prefix+'[0-9]+$', 'i');
Models.Tag
.findOne()
.where({
alias: regexp
})
.sort('-alias')
.exec(function (err, tag){
if(err) return next(err);
// Remove prefix and try parsing number
var lastId = 100;
if(tag){
// Remove prefix
var number = tag.alias.toLowerCase().replace(prefix, '');
// Get number from it
number = parseInt(number);
if(number) lastId = number;
}
console.log('lastAliasNumber', lastId);
next(null, lastId);
});
},
There is no ready way to do this kind of sorting within MongoDB. As your field is a string field, it will be sorted by the rules of string sorting and there is no way to do variable type sorting on one field.
Your best bet (assuming you cannot simply use an integer type and wish to keep only one field) would be to work out the theoretical maximum number of entries and pad your strings with the relevant leading number of 0's accordingly.
EG. assuming a maximum of 1,000,000 entries your strings would be:
test000999
test001200
test000131
Another option would be to have these entries become whole subdocuments with two distinct datatypes.
Consider my quick example documents below
> db.bar.insert({x:{text:"test",num:1}})
WriteResult({ "nInserted" : 1 })
> db.bar.insert({x:{text:"test",num:100}})
WriteResult({ "nInserted" : 1 })
> db.bar.insert({x:{text:"test",num:2}})
WriteResult({ "nInserted" : 1 })
> db.bar.insert({x:{text:"sweet",num:2}})
WriteResult({ "nInserted" : 1 })
> db.bar.insert({x:{text:"sweet",num:1}})
WriteResult({ "nInserted" : 1 })
> db.bar.find().sort({x:1})
{ "_id" : ObjectId("55fa469d695632545d3aff1f"), "x" : { "text" : "sweet", "num" : 1 } }
{ "_id" : ObjectId("55fa469b695632545d3aff1e"), "x" : { "text" : "sweet", "num" : 2 } }
{ "_id" : ObjectId("55fa468a695632545d3aff1b"), "x" : { "text" : "test", "num" : 1 } }
{ "_id" : ObjectId("55fa4695695632545d3aff1d"), "x" : { "text" : "test", "num" : 2 } }
{ "_id" : ObjectId("55fa468f695632545d3aff1c"), "x" : { "text" : "test", "num" : 100 } }
> db.bar.find().sort({x:-1})
{ "_id" : ObjectId("55fa468f695632545d3aff1c"), "x" : { "text" : "test", "num" : 100 } }
{ "_id" : ObjectId("55fa4695695632545d3aff1d"), "x" : { "text" : "test", "num" : 2 } }
{ "_id" : ObjectId("55fa468a695632545d3aff1b"), "x" : { "text" : "test", "num" : 1 } }
{ "_id" : ObjectId("55fa469b695632545d3aff1e"), "x" : { "text" : "sweet", "num" : 2 } }
{ "_id" : ObjectId("55fa469d695632545d3aff1f"), "x" : { "text" : "sweet", "num" : 1 } }

Need to "build" a "key" name in Mongoskin request

I am working on a Node.js app, using Mongoskin and Express.js.
First, here is a simple overview of the MongoDB collection I'm working with :
db.profiles.find()
{ "_id" : ObjectId("5559e6ad8da0dc030010cf64"),
"userid" : "63e9c530-fd60-11e4-a30c-f3b609480e30",
"emailaddr" : { "value" : "x#y.fr", "share" : false },
"fullname" : { "value" : "Azerty Ytreza", "share" : true },
"telnumber" : { "value" : "0606060606", "share" : true }
As you can see, I'm storing multiple objects, following the same architecture (value + boolean)
Depending on what the user will want to share / don't share anymore, I will need to update the "share" value of the good Object.
First, I can't find out how to modify a value stored in an Object.
Referring to this : Modify nested Object value , I thought I could do like this in my Mongoskin requests :
db.collection.update( { _id:...} , { $set: { some_key.param2 : new_info } }
In this case, Node.js is reporting an error, saying "SyntaxError: Unexpected token '.' ".
The thing is that as I said earlier, depending on what the user will want to modify, I won't modify the same "key".
So, I need to build the key name. Example: if the user wants to modify the "share" value of his email address, I will need to update emailaddr.share. But how can I do this using Mongoskin?
I tried different solutions, but it's impossible to do things like :
var key = "emailaddr",
newVal = "true";
key += ".share";
db.collection.update( { _id: ... } { $set: { key : newval } }
Say you want to change the share status of the fullname property :
> var property = "fullname"
> var value = false
You have to dynamically build the object {"fullname.share": false}ยน :
> var updt = {}
> updt[property + ".share"] = value
Then use that object as the parameter to $set:
> db.test.update({"_id" : ObjectId("5559e6ad8da0dc030010cf64")},
... {$set: updt})
// ^^^^
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
1 As a side note, as explained in the doc the quotes (" or ') are mandatory around the name of an object property if it contains a . -- hence the syntax error you mentioned in your question.

Check mongo data key present or not

I have some product data where some product don't have key "images.cover".
now when I try to print all data it show error
Cannot read property 'cover' of undefined.
So I try to make if images.cover key not present then just put var cover = ''; else images.cover value. I'm using nodejs and mongodb
From the error message:
Cannot read property 'cover' of undefined
you can narrow down the error source on the trouble product document to any of the three attributes:
the document doesn't have images field (hence the undefined object),
the images field may be null, and
the covers key may not be present as well.
Let's consider a minimum test case where a sample collection has documents with the above three + one with the images.cover key set:
db.product.insert([
/* 0 */
{
"_id" : 1,
"image" : {
"cover" : "test1",
"url" : "url1"
}
},
/* 1 */
{
"_id" : 2,
"image" : {
"url" : "url2"
}
},
/* 2 */
{
"_id" : 3
},
/* 3 */
{
"_id" : 4,
"image" : {
"cover" : null,
"url" : "url4"
}
}
]);
In mongo shell you can check to see if a key is present or not either by using native JavaScript methods or using mongodb's $exists operator. For the former, you could try:
var cover = "", covers = [];
db.product.find().forEach(function (doc){
var cover = "";
if ((doc.image !== undefined) && (typeof(doc.image.cover) !== "undefined") && (doc.image.cover !== undefined)){
cover = doc["image"].cover;
}
covers.push(cover);
});
print(covers); /* will print to mongo shell:
{
"0" : "test1",
"1" : "",
"2" : "",
"3" : null
}
*/
Using $exists operator with its value set to true, this searches for documents that contain the field, including documents where the field value is null. So using this route is probably not going to work in your example since you would like to assign the covers variable for unmatched documents as well:
var cover = "", covers = [];
db.product.find({ "image.cover": {$exists : true} }).forEach( function(doc) {
covers.push(doc["image"].cover);
});
print(covers); /* this will print to mongo shell:
{
"0" : "test1",
"1" : null
}
*/

Node.js - Nested array in Jade view

Using Mongoose, I have a model Page with an embedded model of Feeds. When i go to /pages, the page.title shows up for each page, but feeds data does not. how should i modify this code to properly display the data from the feeds array? thanks a million
db.pages exmaple:
{ "title" : "testing feeds", "_id" : ObjectId("123456"), "feeds" : [
{ "0" : { "name" : "twitter", "key" : "1234" },
"1" : { "name" : "flickr", "key" : "5678" },
}] }
web.js
app.get('/pages.:format?', function(req, res) {
Page.find({}, function(err, pages) {
switch (req.params.format) {
case 'json':
res.send(pages.map(function(d) {
return d.toObject();
}));
break;
default:
res.render('pages/index.jade', {
locals: {
title: 'ClrTouch | Pages',
pages: pages,
feeds: pages.feed,
}
});
}
});
});
view
- each page in pages
div.page
div.pagetitle= page.title
ul
- each feed in page.feeds
li.pagefeedname= feed.name
li.pagefeedkey= feed.key
with what i have, a list is generated in the view but the list items are empty. Thanks.
Is the model that you have here what you are also testing with? If so, then the reason your list is generated but nothing is displayed is because you do not currently have values in either.
li.pagefeedname=feed.name = "0" : { "name" : "", "key" : "" }
Try giving your feed name/keys some values and see how that plays out.
Otherwise what you have should work
tuddy,
I suggest you try like this:
Page.find().lean().exec(function(err,pages){
// TODO
});

Resources