Dynamically change JSTree sort order - jstree

I'm using JSTree to display a small Windows Explorer-like appearance, everything is perfect but I have to implement sorting option also, is there anyway that I can have my tree sorting order dynamically changed? For example I can have a button that allows user to sort contents based on name (asc or desc), size, change date or even type. How can I perform it?
I think there is something wrong with JSTree sort plugin, or at least I cannot understand how it works!
This is what I do in order to change sort based on user interaction:
treeInst = $('#divWindowsExplorer').jstree(true);
var root = treeInst.get_node('j1_1');
$.jstree.defaults.sort = function (a, b) {
return this.get_text(a) < this.get_text(b) ? -1 : 1;
};
$("#divWindowsExplorer").jstree(true).sort(root, true);
$("#divWindowsExplorer").jstree(true).redraw_node(root, true);

Try with sort options.
$("#plugins5").jstree({
"plugins" : [ "sort" ],
'sort' : function(a, b) {
// you can do custom sorting here
// based on your user action you can return 1 or -1
// 1 show on top -1 for show bottom
}
});
For more info click here

root node doesn't work when we call sort, I did sort my tree dynamically by calling sort and redraw_node function with the id of the first node of my tree instead of root.
Hope this is helpful.

Related

Meteor js mongodb SUM collection documents is incomplete

I have a problem which I do not know where to start. I have a button that calculates total amount from all matching documents in a collection. ie: certain month, year and branch calculations. So far, when I click it first time it gives me "y" amount, second time returns "x" amount.
What I suppose is that collection documents is incomplete when first time.
How may I solve this? Please excuse me if this has already been answered, I have looked around unsuccessfully.
When button is clicked, in template events executes:
'click #calculate': function(event,instance){
var _transactions = instance.Transactions().fetch();
var capital = _transactions.reduce(function(sum, row){
return row.is_accountable ? sum + row.transaction_amount : sum + 0;
}, 0);
instance.capital.set(capital);
}
Since you're using Blaze you might consider making this computation a helper instead of an event handler. That way (a) the user doesn't need to click to get the sum, (b) the total will always be up-to-date even if the data changes reactively.
Template.myTemplate.helper({
sum(){
s = 0;
Transactions.find().map((doc)={
s += doc.is_accountable ? doc.transaction_amount : 0;
});
return s;
}
});

Meteor, mongodb - accessing an object inside an array

Alright, so I have a collection called Polls. Inside the Polls "table" there is an attribute called choiceObjects which is an array of objects. Each object inside this array has its own attributes. What I need to do is update one of the attributes there. Ill give you a screen shot so you can better visualise what Im talking about
As you can see the choice objects have attributes like body, country etc. There is another attribute called pollid which is set to optional and therefore you cant see it right now. I need to update this pollid attribute now that I have acess to the pollid
Polls.update(
{ _id: pollId },
{ "$set": { "choiceObjects": { pollid: pollId } } }
); //this is kind of what Im trying to do but this isnt right
Since then... I have further tried the following :
var selectedpoll = Polls.findOne(pollId);
console.log(selectedpoll);
//Polls.update( selectedpoll, {"$set"{'choiceObjects.$.pollId':pollId}},false, true );
but when i try that i get the error : the positional operator did not find the match needed from the query. unexpanded update: choiceObjects.$.pollId
If I understand your objective correctly, you want to update (or add) pollid to all objects in the choiceObjects array. Unfortunately $, $push, $addToSet only work with single elements AFAIK.
This might not be what you are looking for but one possible and very obvious way to approach this problem would be to update the entire array in the collection i.e.
var choiceObjects = Polls.findOne({_id: pollId}).choiceObjects;
for (var i = 0; i < choiceObjects.length; i++) {
choiceObjects[i].pollid = pollid;
}
Polls.update({_id: pollid}, {choiceObjects: choiceObjects});

Build a reactive publication with additional fields in each document

I want to make a publication with several additional fields, but I don't want to either use Collection.aggregate and lose my publication updates when the collection change (so I can't just use self.added in it either).
I plan to use Cursor.observeChanges in order to achieve that. I have two major constraints:
I don't want to publish all the documents fields
I want to use some of the unpublished fields to create new ones. For example, I have a field item where I store an array of item _id. I don't want to publish it, but I want to publish a item_count field with the length of my field array
Here comes the approach:
I plan to chain find queries. I never did that so I wonder if it possible. The general (simplified) query structure would be like this: http://jsfiddle.net/Billybobbonnet/1cgrqouj/ (I cant get the code properly displayed here)
Based on the count example in Meteor documentation, I store my query in a variable handle in order to stop the changes notification if a client unsubscribes:
self.onStop(function () {
handle.stop();
});
I add a flag initializing = true; before my query and I set it to true just before calling self.ready();. I use this flag to change my itemCount variable only if it is the publication is initialized. So basically, I change my switch like that:
switch (field) {
case "item"
if (!initializing)
itemCount = raw_document.item.length;
break;
default:
}
I wanted to check that this approach is good and possible before committing into big changes in my code. Can someone confirm me if this is the right way to go?
It's relatively easy to keep fields private even if they are part of the database query. The last argument to self.added is the object being passed to the client, so you can strip/modify/delete fields you are sending to the client.
Here's a modified version of your fiddle. This should do what you are asking for. (To be honest I'm not sure why you had anything chained after the observeChanges function in your fiddle, so maybe I'm misunderstanding you, but looking at the rest of your question this should be it. Sorry if I got it wrong.)
var self = this;
// Modify the document we are sending to the client.
function filter(doc) {
var length = doc.item.length;
// White list the fields you want to publish.
var docToPublish = _.pick(doc, [
'someOtherField'
]);
// Add your custom fields.
docToPublish.itemLength = length;
return docToPublish;
}
var handle = myCollection.find({}, {fields: {item:1, someOtherField:1}})
// Use observe since it gives us the the old and new document when something is changing.
// If this becomes a performance issue then consider using observeChanges,
// but its usually a lot simpler to use observe in cases like this.
.observe({
added: function(doc) {
self.added("myCollection", doc._id, filter(doc));
},
changed: function(newDocument, oldDocument)
// When the item count is changing, send update to client.
if (newDocument.item.length !== oldDocument.item.length)
self.changed("myCollection", newDocument._id, filter(newDocument));
},
removed: function(doc) {
self.removed("myCollection", doc._id);
});
self.ready();
self.onStop(function () {
handle.stop();
});
To solve your first problem, you need to tell MongoDB what fields it should return in the cursor. Leave out the fields you don't want:
MyCollection.find({}, {fields: {'a_field':1}});
Solving your second problem is also pretty easy, I would suggest using the collection helpers packages. You could accomplish this easily, like so:
// Add calculated fields to MyCollection.
MyCollection.helpers({
item_count: function() {
return this.items.length;
}
});
This will be run before an object is added to a cursor, and will create properties on the returned objects that are calculated dynamically, not stored in MongoDB.

Mongo -Select parent document with maximum child documents count, Faster way?

I'm quite new to mongo, and trying to get work following query.and is working fine too, But it's taking a little bit more time. I think I'm doing something wrong.
There are many number of documents in a collection parent, near about 6000. Each document has certain number of childs (childs is an another collection with 40000 documents in it). parents & childs are associated with each other by an attribute in the document called parent_id. Please see the following code. Following code takes approximate 1 minute to execute the queries. I don't think mongo should take that much time.
function getChildMaxDocCount(){
var maxLen = 0;
var bigSizeParent = null;
db.parents.find().forEach(function (parent){
var currentcount = db.childs.count({parent_id:parent._id});
if(currcount > maxLen){
maxLen = currcount;
bigSizeParent = parent._id;
}
});
printjson({"maxLen":maxLen, "bigSizeParent":bigSizeParent });
}
Is there any feasible/optimal way to achieve this?
If I got you right, you want to have the parent with the most childs. This is easy to accomplish using the aggregation framework. When each child only can have one parent, the aggregation query would look like this
db.childs.aggregate(
{ $group: { _id:"$parent_id", children:{$sum:1} } },
{ $sort: { "children":-1 } },
{ $limit : 1 }
);
Which should return a document like:
{ _id:"SomeParentId", children:15}
If a child can have more than one parent, it heavily depends on the data modeling how the query would look like.
Have a look at the aggregation framework documentation for details.
Edit: Some explanation
The aggregation pipeline takes every document it is told do do so through a series of steps in a way that all documents are first processed through the first step and the resulting documents are put into the next step.
Step 1: Grouping
We group all documents into new documents (virtual ones, if you want) and tell mongod to increment the field children by one for each document which has the same parent_id. Since we are referring to a field of the current document, we need to add a $ sign.
Step 2: Sorting
Now that we have a bunch of documents which hold the parent_id and the number of children this parent has, we sort it by the children field in descending (-1) order.
Step3: Limiting
Since we are only interested in the parent_id which has the most children, we only let mongod return the first document after sorting.

How to "(WHERE) column = column" in Mongo?

I like Mongo for simple things so I was hoping to use it for something more advanced. And that worked fine until I needed this:
UPDATE tbl SET a = b WHERE c <> 0
The a = b part is what I can't figure out. I tried mongodb.org, but I can't find it there. I also looked for WHERE a = b but I can't find that either.
An alternative is so fetch all rows and than update them individually, but I don't like that. It has to be simpler.
Thanks.
You want to check the documentation for updating.
http://www.mongodb.org/display/DOCS/Updating
Your code might look like:
db.tbl.update( { c:{$ne:0}}, { $set: { a : b } } );
If you need to brush up on advanced queries (e.g. using $ne), then check here:
http://www.mongodb.org/display/DOCS/Advanced+Queries
EDIT:
Apparently you can't update with data from the same document.
MongoDB: Updating documents using data from the same document
EDIT 2 (solution with map reduce):
var c = new Mongo();
var db = c.getDB('db')
var s = db.getCollection('s')
s.drop();
s.save({z:1,q:5});
s.save({z:11,q:55});
db.runCommand({
mapreduce:'s',
map:function(){
var i = this._id; //we will emit with a unique key. _id in this case
this._id=undefined; //strange things happen with merge if you leave the id in
//update your document with access to all fields!
this.z=this.q;
emit(i,this);
},
query:{z:1}, //apply to only certain documents
out:{merge:'s'} //results get merged (overwrite themselves in collection)
});
//now take a look
s.find();