Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial import.

  • Loading branch information...
commit ecb39d19c85d473770cfb93c446cec1a3df3b0ea 0 parents
@marcboeker authored
41 README.md
@@ -0,0 +1,41 @@
+# What's this?
+
+MongoDB admin is a dirty attempt to build a web frontend for MongoDB like
+CouchDBs Futon or PHPMyAdmin. It ist still very very pre-alpha but MongoDB
+admin is looking for interested developers that want to make it big.
+
+MongoDB admin is pure JavaScript (jQuery) and HTML/CSS with a REST backend
+written in Python. The REST API included in MongoDB has some issues[1], that
+make it unpossible at the moment to use MongoDBs full advantages.
+
+[1] Supplying ?filter__id=5sdf34sdfsdf => results in _id=5, but
+?filter__id=asdf works well.
+
+# Installation
+
+I assume you have Python 2.6 installed.
+
+## Install python requirements for REST API
+
+<pre>
+sudo easy_install cherrypy
+sudo easy_install pymongo
+</pre>
+
+## Get source
+
+<pre>
+git clone git://github.com/marcboeker/mongodb-admin.git
+</pre>
+
+## Run REST server
+
+<pre>
+cd mongodb-admin
+python rest.py
+</pre>
+
+# Contribution
+
+Everyone that has interest in maintaining or contribute to this
+project is welcome.
125 rest.py
@@ -0,0 +1,125 @@
+from pymongo.connection import Connection
+from pymongo.objectid import ObjectId
+from pymongo.dbref import DBRef
+
+import datetime
+import json
+import os
+
+import cherrypy
+
+conn = Connection('127.0.0.1', pool_size=10)
+
+class ComplexEncoder(json.JSONEncoder):
+ """Advise JSON encoder to encode some datatypes a special way.
+ """
+
+ def default(self, obj):
+ # Handle MongoDB ObjectId
+ if isinstance(obj, ObjectId):
+ return obj.url_encode()
+ # Datetime values
+ elif isinstance(obj, datetime.datetime):
+ return str(obj)
+ # DBRefs
+ elif isinstance(obj, DBRef):
+ return json.dumps({
+ '$id': obj.id.url_encode(), '$ns': obj.collection
+ })
+ return json.JSONEncoder.default(self, obj)
+
+class Root(object):
+ """Main entry class.
+ """
+
+
+ def default(self, *args, **kwargs):
+ """Catch all requests.
+ """
+
+ # /db/ => show all collections of a database
+ if len(args) == 1:
+ db = args[0]
+ cursor = conn[db].collection_names()
+
+ # return collections in JSON
+ return json.dumps({
+ 'database': db,
+ 'collections': cursor,
+ 'total_rows': len(cursor)
+ })
+ # /db/collection/ => show first 10 docs in collection
+ elif len(args) == 2:
+ db, coll = args
+
+ # Supply filter as normal pymongo.collection.find() spec
+ if 'filter' in kwargs and len(kwargs['filter']) > 0:
+ filter = json.loads(kwargs['filter'])
+ else:
+ filter = {}
+
+ cursor = conn[db][coll].find(filter)
+
+ # Sorting
+ if 'sort' in kwargs and len(kwargs['sort']) > 0:
+ sort = json.loads(kwargs['sort'])
+ cursor = cursor.sort(sort)
+ else:
+ sort = {}
+
+ # Limiting
+ try:
+ limit = int(kwargs['limit'])
+ cursor = cursor.limit(limit)
+ except:
+ limit = 0
+
+ # Offset
+ try:
+ skip = int(kwargs['skip'])
+ cursor = cursor.skip(skip)
+ except:
+ skip = 0
+
+ # I'm shure there is a better way
+ docs = []
+ for doc in cursor:
+ docs.append(doc.to_dict())
+
+ # We got everything? Let's go
+ return json.dumps({
+ 'database': db,
+ 'collection': coll,
+ 'offset': skip,
+ 'documents': docs,
+ 'total_rows': len(docs),
+ 'query': filter,
+ }, cls=ComplexEncoder, skipkeys=True)
+ # / => show all databases
+ else:
+ cursor = conn.database_names()
+
+ return json.dumps({
+ 'databases': cursor,
+ 'total_rows': len(cursor)
+ })
+ default.exposed = True
+
+# Some cherrypy config vars
+cherrypy.config.update({
+ #'environment': 'production',
+ 'log.screen': True,
+ 'server.process_pool': 10,
+ 'tools.encode.on': True,
+ 'tools.encode.encoding': 'utf-8'
+})
+
+conf = {'/_': {
+ 'tools.staticdir.on': True,
+ 'tools.staticdir.dir': '/'.join([
+ os.path.dirname(os.path.abspath(__file__)), 'web'
+ ])}
+}
+
+# Get cherrypy up and running
+cherrypy.quickstart(Root(), '/', config=conf)
68 web/css/jquery.treeview.css
@@ -0,0 +1,68 @@
+.treeview, .treeview ul {
+ padding: 0;
+ margin: 0;
+ list-style: none;
+}
+
+.treeview ul {
+ background-color: white;
+ margin-top: 4px;
+}
+
+.treeview .hitarea {
+ background: url(/_/img/treeview-default.gif) -64px -25px no-repeat;
+ height: 16px;
+ width: 16px;
+ margin-left: -16px;
+ float: left;
+ cursor: pointer;
+}
+/* fix for IE6 */
+* html .hitarea {
+ display: inline;
+ float:none;
+}
+
+.treeview li {
+ margin: 0;
+ padding: 3px 0pt 3px 16px;
+}
+
+.treeview a.selected {
+ background-color: #eee;
+}
+
+#treecontrol { margin: 1em 0; display: none; }
+
+.treeview .hover { color: red; cursor: pointer; }
+
+.treeview li { background: url(/_/img/treeview-default-line.gif) 0 0 no-repeat; }
+.treeview li.collapsable, .treeview li.expandable { background-position: 0 -176px; }
+
+.treeview .expandable-hitarea { background-position: -80px -3px; }
+
+.treeview li.last { background-position: 0 -1766px }
+.treeview li.lastCollapsable, .treeview li.lastExpandable { background-image: url(/_/img/treeview-default.gif); }
+.treeview li.lastCollapsable { background-position: 0 -111px }
+.treeview li.lastExpandable { background-position: -32px -67px }
+
+.treeview div.lastCollapsable-hitarea, .treeview div.lastExpandable-hitarea { background-position: 0; }
+
+.treeview-red li { background-image: url(/_/img/treeview-red-line.gif); }
+.treeview-red .hitarea, .treeview-red li.lastCollapsable, .treeview-red li.lastExpandable { background-image: url(/_/img/treeview-red.gif); }
+
+.treeview-black li { background-image: url(/_/img/treeview-black-line.gif); }
+.treeview-black .hitarea, .treeview-black li.lastCollapsable, .treeview-black li.lastExpandable { background-image: url(/_/img/treeview-black.gif); }
+
+.treeview-gray li { background-image: url(/_/img/treeview-gray-line.gif); }
+.treeview-gray .hitarea, .treeview-gray li.lastCollapsable, .treeview-gray li.lastExpandable { background-image: url(/_/img/treeview-gray.gif); }
+
+.treeview-famfamfam li { background-image: url(/_/img/treeview-famfamfam-line.gif); }
+.treeview-famfamfam .hitarea, .treeview-famfamfam li.lastCollapsable, .treeview-famfamfam li.lastExpandable { background-image: url(/_/img/treeview-famfamfam.gif); }
+
+
+.filetree li { padding: 3px 0 2px 16px; }
+.filetree span.folder, .filetree span.file { padding: 1px 0 1px 16px; display: block; }
+.filetree span.folder { background: url(/_/img/folder.gif) 0 0 no-repeat; }
+.filetree li.expandable span.folder { background: url(/_/img/folder-closed.gif) 0 0 no-repeat; }
+.filetree span.file { background: url(/_/img/file.gif) 0 0 no-repeat; }
BIN  web/img/file.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  web/img/folder-closed.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  web/img/folder.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  web/img/minus.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  web/img/plus.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  web/img/treeview-black-line.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  web/img/treeview-black.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  web/img/treeview-default-line.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  web/img/treeview-default.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  web/img/treeview-famfamfam-line.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  web/img/treeview-famfamfam.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  web/img/treeview-gray-line.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  web/img/treeview-gray.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  web/img/treeview-red-line.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  web/img/treeview-red.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 web/index.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
+ <title>MongoDB Admin</title>
+
+ <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript"></script>
+
+ <script src="/_/js/mongodb.js" type="text/javascript"></script>
+ <script src="/_/js/mongodb.templates.js" type="text/javascript"></script>
+ <script src="/_/js/jquery.treeview.js" type="text/javascript"></script>
+
+ <link rel="stylesheet" href="/_/css/jquery.treeview.css" />
+
+ <script>
+ $(document).ready(function() {
+ MongoDB.getDatabases(MongoDB.templates.databases);
+ });
+ </script>
+</head>
+
+<body>
+ Database: <select id="databases"></select> &gt; Collection: <select id="collections"></select>
+
+ <h1>Documents</h1>
+ <div id="documents"></div>
+</body>
+</html>
72 web/js/jquery.treeview.async.js
@@ -0,0 +1,72 @@
+/*
+ * Async Treeview 0.1 - Lazy-loading extension for Treeview
+ *
+ * http://bassistance.de/jquery-plugins/jquery-plugin-treeview/
+ *
+ * Copyright (c) 2007 Jörn Zaefferer
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * Revision: $Id$
+ *
+ */
+
+;(function($) {
+
+function load(settings, root, child, container) {
+ $.getJSON(settings.url, {root: root}, function(response) {
+ function createNode(parent) {
+ var current = $("<li/>").attr("id", this.id || "").html("<span>" + this.text + "</span>").appendTo(parent);
+ if (this.classes) {
+ current.children("span").addClass(this.classes);
+ }
+ if (this.expanded) {
+ current.addClass("open");
+ }
+ if (this.hasChildren || this.children && this.children.length) {
+ var branch = $("<ul/>").appendTo(current);
+ if (this.hasChildren) {
+ current.addClass("hasChildren");
+ createNode.call({
+ text:"placeholder",
+ id:"placeholder",
+ children:[]
+ }, branch);
+ }
+ if (this.children && this.children.length) {
+ $.each(this.children, createNode, [branch])
+ }
+ }
+ }
+ $.each(response, createNode, [child]);
+ $(container).treeview({add: child});
+ });
+}
+
+var proxied = $.fn.treeview;
+$.fn.treeview = function(settings) {
+ if (!settings.url) {
+ return proxied.apply(this, arguments);
+ }
+ var container = this;
+ load(settings, "source", this, container);
+ var userToggle = settings.toggle;
+ return proxied.call(this, $.extend({}, settings, {
+ collapsed: true,
+ toggle: function() {
+ var $this = $(this);
+ if ($this.hasClass("hasChildren")) {
+ var childList = $this.removeClass("hasChildren").find("ul");
+ childList.empty();
+ load(settings, this.id, childList, container);
+ }
+ if (userToggle) {
+ userToggle.apply(this, arguments);
+ }
+ }
+ }));
+};
+
+})(jQuery);
251 web/js/jquery.treeview.js
@@ -0,0 +1,251 @@
+/*
+ * Treeview 1.4 - jQuery plugin to hide and show branches of a tree
+ *
+ * http://bassistance.de/jquery-plugins/jquery-plugin-treeview/
+ * http://docs.jquery.com/Plugins/Treeview
+ *
+ * Copyright (c) 2007 Jörn Zaefferer
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * Revision: $Id: jquery.treeview.js 4684 2008-02-07 19:08:06Z joern.zaefferer $
+ *
+ */
+
+;(function($) {
+
+ $.extend($.fn, {
+ swapClass: function(c1, c2) {
+ var c1Elements = this.filter('.' + c1);
+ this.filter('.' + c2).removeClass(c2).addClass(c1);
+ c1Elements.removeClass(c1).addClass(c2);
+ return this;
+ },
+ replaceClass: function(c1, c2) {
+ return this.filter('.' + c1).removeClass(c1).addClass(c2).end();
+ },
+ hoverClass: function(className) {
+ className = className || "hover";
+ return this.hover(function() {
+ $(this).addClass(className);
+ }, function() {
+ $(this).removeClass(className);
+ });
+ },
+ heightToggle: function(animated, callback) {
+ animated ?
+ this.animate({ height: "toggle" }, animated, callback) :
+ this.each(function(){
+ jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]();
+ if(callback)
+ callback.apply(this, arguments);
+ });
+ },
+ heightHide: function(animated, callback) {
+ if (animated) {
+ this.animate({ height: "hide" }, animated, callback);
+ } else {
+ this.hide();
+ if (callback)
+ this.each(callback);
+ }
+ },
+ prepareBranches: function(settings) {
+ if (!settings.prerendered) {
+ // mark last tree items
+ this.filter(":last-child:not(ul)").addClass(CLASSES.last);
+ // collapse whole tree, or only those marked as closed, anyway except those marked as open
+ this.filter((settings.collapsed ? "" : "." + CLASSES.closed) + ":not(." + CLASSES.open + ")").find(">ul").hide();
+ }
+ // return all items with sublists
+ return this.filter(":has(>ul)");
+ },
+ applyClasses: function(settings, toggler) {
+ this.filter(":has(>ul):not(:has(>a))").find(">span").click(function(event) {
+ toggler.apply($(this).next());
+ }).add( $("a", this) ).hoverClass();
+
+ if (!settings.prerendered) {
+ // handle closed ones first
+ this.filter(":has(>ul:hidden)")
+ .addClass(CLASSES.expandable)
+ .replaceClass(CLASSES.last, CLASSES.lastExpandable);
+
+ // handle open ones
+ this.not(":has(>ul:hidden)")
+ .addClass(CLASSES.collapsable)
+ .replaceClass(CLASSES.last, CLASSES.lastCollapsable);
+
+ // create hitarea
+ this.prepend("<div class=\"" + CLASSES.hitarea + "\"/>").find("div." + CLASSES.hitarea).each(function() {
+ var classes = "";
+ $.each($(this).parent().attr("class").split(" "), function() {
+ classes += this + "-hitarea ";
+ });
+ $(this).addClass( classes );
+ });
+ }
+
+ // apply event to hitarea
+ this.find("div." + CLASSES.hitarea).click( toggler );
+ },
+ treeview: function(settings) {
+
+ settings = $.extend({
+ cookieId: "treeview"
+ }, settings);
+
+ if (settings.add) {
+ return this.trigger("add", [settings.add]);
+ }
+
+ if ( settings.toggle ) {
+ var callback = settings.toggle;
+ settings.toggle = function() {
+ return callback.apply($(this).parent()[0], arguments);
+ };
+ }
+
+ // factory for treecontroller
+ function treeController(tree, control) {
+ // factory for click handlers
+ function handler(filter) {
+ return function() {
+ // reuse toggle event handler, applying the elements to toggle
+ // start searching for all hitareas
+ toggler.apply( $("div." + CLASSES.hitarea, tree).filter(function() {
+ // for plain toggle, no filter is provided, otherwise we need to check the parent element
+ return filter ? $(this).parent("." + filter).length : true;
+ }) );
+ return false;
+ };
+ }
+ // click on first element to collapse tree
+ $("a:eq(0)", control).click( handler(CLASSES.collapsable) );
+ // click on second to expand tree
+ $("a:eq(1)", control).click( handler(CLASSES.expandable) );
+ // click on third to toggle tree
+ $("a:eq(2)", control).click( handler() );
+ }
+
+ // handle toggle event
+ function toggler() {
+ $(this)
+ .parent()
+ // swap classes for hitarea
+ .find(">.hitarea")
+ .swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
+ .swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea )
+ .end()
+ // swap classes for parent li
+ .swapClass( CLASSES.collapsable, CLASSES.expandable )
+ .swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
+ // find child lists
+ .find( ">ul" )
+ // toggle them
+ .heightToggle( settings.animated, settings.toggle );
+ if ( settings.unique ) {
+ $(this).parent()
+ .siblings()
+ // swap classes for hitarea
+ .find(">.hitarea")
+ .replaceClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
+ .replaceClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea )
+ .end()
+ .replaceClass( CLASSES.collapsable, CLASSES.expandable )
+ .replaceClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
+ .find( ">ul" )
+ .heightHide( settings.animated, settings.toggle );
+ }
+ }
+
+ function serialize() {
+ function binary(arg) {
+ return arg ? 1 : 0;
+ }
+ var data = [];
+ branches.each(function(i, e) {
+ data[i] = $(e).is(":has(>ul:visible)") ? 1 : 0;
+ });
+ $.cookie(settings.cookieId, data.join("") );
+ }
+
+ function deserialize() {
+ var stored = $.cookie(settings.cookieId);
+ if ( stored ) {
+ var data = stored.split("");
+ branches.each(function(i, e) {
+ $(e).find(">ul")[ parseInt(data[i]) ? "show" : "hide" ]();
+ });
+ }
+ }
+
+ // add treeview class to activate styles
+ this.addClass("treeview");
+
+ // prepare branches and find all tree items with child lists
+ var branches = this.find("li").prepareBranches(settings);
+
+ switch(settings.persist) {
+ case "cookie":
+ var toggleCallback = settings.toggle;
+ settings.toggle = function() {
+ serialize();
+ if (toggleCallback) {
+ toggleCallback.apply(this, arguments);
+ }
+ };
+ deserialize();
+ break;
+ case "location":
+ var current = this.find("a").filter(function() { return this.href.toLowerCase() == location.href.toLowerCase(); });
+ if ( current.length ) {
+ current.addClass("selected").parents("ul, li").add( current.next() ).show();
+ }
+ break;
+ }
+
+ branches.applyClasses(settings, toggler);
+
+ // if control option is set, create the treecontroller and show it
+ if ( settings.control ) {
+ treeController(this, settings.control);
+ $(settings.control).show();
+ }
+
+ return this.bind("add", function(event, branches) {
+ $(branches).prev()
+ .removeClass(CLASSES.last)
+ .removeClass(CLASSES.lastCollapsable)
+ .removeClass(CLASSES.lastExpandable)
+ .find(">.hitarea")
+ .removeClass(CLASSES.lastCollapsableHitarea)
+ .removeClass(CLASSES.lastExpandableHitarea);
+ $(branches).find("li").andSelf().prepareBranches(settings).applyClasses(settings, toggler);
+ });
+ }
+ });
+
+ // classes used by the plugin
+ // need to be styled via external stylesheet, see first example
+ var CLASSES = $.fn.treeview.classes = {
+ open: "open",
+ closed: "closed",
+ expandable: "expandable",
+ expandableHitarea: "expandable-hitarea",
+ lastExpandableHitarea: "lastExpandable-hitarea",
+ collapsable: "collapsable",
+ collapsableHitarea: "collapsable-hitarea",
+ lastCollapsableHitarea: "lastCollapsable-hitarea",
+ lastCollapsable: "lastCollapsable",
+ lastExpandable: "lastExpandable",
+ last: "last",
+ hitarea: "hitarea"
+ };
+
+ // provide backwards compability
+ $.fn.Treeview = $.fn.treeview;
+
+})(jQuery);
13 web/js/mongodb.js
@@ -0,0 +1,13 @@
+MongoDB = {
+ getDatabases: function(callBack) {
+ $.getJSON('/', {}, callBack);
+ },
+
+ getCollections: function(db, callBack) {
+ $.getJSON('/' + db, {}, callBack);
+ },
+
+ getDocuments: function(db, collection, options, callBack) {
+ $.getJSON('/' + db + '/' + collection + '/', options, callBack);
+ }
+};
81 web/js/mongodb.templates.js
@@ -0,0 +1,81 @@
+MongoDB.templates = {
+ databases: function(data) {
+ $(data.databases).each(function(idx, val) {
+ var option = $('<option />');
+ option.html(val);
+ option.val(val);
+
+ $('#databases').append(option);
+ });
+
+ $('#databases').change(function() {
+ MongoDB.getCollections(this.value, MongoDB.templates.collections);
+ });
+ },
+
+ collections: function(data) {
+ $('#collections').html('');
+ $(data.collections).each(function(idx, val) {
+ var option = $('<option />');
+ option.html(val);
+ option.val(val);
+
+ $('#collections').append(option);
+ });
+ $('#collections').change(function() {
+ MongoDB.getDocuments(data.database, this.value, MongoDB.templates.documents);
+ });
+ },
+
+ buildDocTree: function(obj) {
+ var type = typeof obj;
+
+ var ul = $('<ul />');
+ if (type == 'string' || type == 'number' || type == 'boolean') {
+ var ul_inner = $('<ul />');
+ var li = $('<li />');
+ var span = $('<span />');
+
+ span.html(obj.toString());
+ li.append(span);
+ ul_inner.append(li);
+
+ return ul_inner;
+ } else if (type == 'object') {
+ for (var key in obj) {
+ var li = $('<li />');
+ var span = $('<span />');
+ span.html(key);
+ li.append(span);
+ li.append(MongoDB.templates.buildDocTree(obj[key]));
+ ul.append(li);
+ }
+ return ul;
+ } else if (type == 'array') {
+ var ul_inner = $('<ul />');
+ $(obj).each(function(idx, val) {
+ var li = $('<li />');
+ li.append(MongoDB.templates.buildDocTree(val));
+ ul_inner.append(li);
+ });
+ return ul_inner;
+ }
+ return ul;
+ },
+
+ documents: function(data) {
+ $('#documents').html('');
+
+ var ul = $('<ul />');
+ $(data.documents).each(function(idx, val) {
+ var li = $('<li />')
+ li.html(val._id || '[no name]');
+ ul.append(li);
+
+ delete val._id;
+ li.append(MongoDB.templates.buildDocTree(val).treeview({collapsed: true}));
+ });
+ $('#documents').append(ul);
+ $('#documents').append('<p>Total Documents: ' + data.total_rows + '</p>');
+ },
+};
Please sign in to comment.
Something went wrong with that request. Please try again.