How do I describe a collection in Mongo? - mongodb

So this is Day 3 of learning Mongo Db. I'm coming from the MySql universe...
A lot of times when I need to write a query for a MySql table I'm unfamiliar with, I would use the "desc" command - basically telling me what fields I should include in my query.
How would I do that for a Mongo db? I know, I know...I'm searching for a schema in a schema-less database. =) But how else would users know what fields to use in their queries?
Am I going at this the wrong way? Obviously I'm trying to use a MySql way of doing things in a Mongo db. What's the Mongo way?

Type the below query in editor / mongoshell
var col_list= db.emp.findOne();
for (var col in col_list) { print (col) ; }
output will give you name of columns in collection :
_id
name
salary

There is no good answer here. Because there is no schema, you can't 'describe' the collection. In many (most?) MongoDb applications, however, the schema is defined by the structure of the object hierarchy used in the writing application (java or c# or whatever), so you may be able to reflect over the object library to get that information. Otherwise there is a bit of trial and error.

This is my day 30 or something like that of playing around with MongoDB. Unfortunately, we have switched back to MySQL after working with MongoDB because of my company's current infrastructure issues. But having implemented the same model on both MongoDB and MySQL, I can clearly see the difference now.
Of course, there is a schema involved when dealing with schema-less databases like MongoDB, but the schema is dictated by the application, not the database. The database will shove in whatever it is given. As long as you know that admins are not secretly logging into Mongo and making changes, and all access to the database is controller through some wrapper, the only place you should look at for the schema is your model classes. For instance, in our Rails application, these are two of the models we have in Mongo,
class Consumer
include MongoMapper::Document
key :name, String
key :phone_number, String
one :address
end
class Address
include MongoMapper::EmbeddedDocument
key :street, String
key :city, String
key :state, String
key :zip, String
key :state, String
key :country, String
end
Now after switching to MySQL, our classes look like this,
class Consumer < ActiveRecord::Base
has_one :address
end
class Address < ActiveRecord::Base
belongs_to :consumer
end
Don't get fooled by the brevity of the classes. In the latter version with MySQL, the fields are being pulled from the database directly. In the former example, the fields are right there in front of our eyes.
With MongoDB, if we had to change a particular model, we simply add, remove, or modify the fields in the class itself and it works right off the bat. We don't have to worry about keeping the database tables/columns in-sync with the class structure. So if you're looking for the schema in MongoDB, look towards your application for answers and not the database.
Essentially I am saying the exactly same thing as #Chris Shain :)

While factually correct, you're all making this too complex. I think the OP just wants to know what his/her data looks like. If that's the case, you can just
db.collectionName.findOne()
This will show one document (aka. record) in the database in a pretty format.

I had this need too, Cavachon. So I created an open source tool called Variety which does exactly this: link
Hopefully you'll find it to be useful. Let me know if you have questions, or any issues using it.
Good luck!

AFAIK, there isn't a way and it is logical for it to be so.
MongoDB being schema-less allows a single collection to have a documents with different fields. So there can't really be a description of a collection, like the description of a table in the relational databases.
Though this is the case, most applications do maintain a schema for their collections and as said by Chris this is enforced by your application.
As such you wouldn't have to worry about first fetching the available keys to make a query. You can just ask MongoDB for any set of keys (i.e the projection part of the query) or query on any set of keys. In both cases if the keys specified exist on a document they are used, otherwise they aren't. You will not get any error.
For instance (On the mongo shell) :
If this is a sample document in your people collection and all documents follow the same schema:
{
name : "My Name"
place : "My Place"
city : "My City"
}
The following are perfectly valid queries :
These two will return the above document :
db.people.find({name : "My Name"})
db.people.find({name : "My Name"}, {name : 1, place :1})
This will not return anything, but will not raise an error either :
db.people.find({first_name : "My Name"})
This will match the above document, but you will have only the default "_id" property on the returned document.
db.people.find({name : "My Name"}, {first_name : 1, location :1})

print('\n--->', Object.getOwnPropertyNames(db.users.findOne())
.toString()
.replace(/,/g, '\n---> ') + '\n');
---> _id
---> firstName
---> lastName
---> email
---> password
---> terms
---> confirmed
---> userAgent
---> createdAt

This is an incomplete solution because it doesn't give you the exact types, but useful for a quick view.
const doc = db.collectionName.findOne();
for (x in doc) {
print(`${x}: ${typeof doc[x]}`)
};

If you're OK with running a Map / Reduce, you can gather all of the possible document fields.
Start with this post.
The only problem here is that you're running a Map / Reduce on which can be resource intensive. Instead, as others have suggested, you'll want to look at the code that writes the actual data.
Just because the database doesn't have a schema doesn't mean that there is no schema. Generally speaking the schema information will be in the code.

I wrote a small mongo shell script that may help you.
https://gist.github.com/hkasera/9386709
Let me know if it helps.

You can use a UI tool mongo compass for mongoDb. This shows all the fields in that collection and also shows the variation of data in it.

If you are using NodeJS and want to get the all the field names using the API request, this code works for me-
let arrayResult = [];
db.findOne().exec(function (err, docs)){
if(err)
//show error
const JSONobj = JSON.parse(JSON.stringify(docs));
for(let key in JSONobj) {
arrayResult.push(key);
}
return callback(null, arrayResult);
}
The arrayResult will give you entire field/ column names
Output-
[
"_id",
"emp_id",
"emp_type",
"emp_status",
"emp_payment"
]
Hope this works for you!

Consider you have collection called people and you want to find the fields and it's data-types. you can use below query
function printSchema(obj) {
for (var key in obj) {
print( key, typeof obj[key]) ;
}
};
var obj = db.people.findOne();
printSchema(obj)
The result of this query will be like below,

you can use Object.keys like in JavaScript
Object.keys(db.movies.findOne())

Related

Get Schema using collection name mongoose

Lets say I have a collection "employees" in mongodb.now i want to get the
Schema of that collection using "mongoose".Can I do that? I want to have the
schema object from the collection name.
import mongoose from 'mongoose';
public getMappers(collectionName): Schema {
let schema = mongoose.model(collectionName).schema;
return schema ;
}
is there any way to do this?
Short answer: No.
Let me explain why? NoSQL DBs are known for the flexibility of the unknown data fields. One document can have a different set of fields from another sibling document. Due to this, a tool can not determine all the fields in your schema (and ponder that fields can be added later as well). However, You can get a superset of fields by looking at all the documents in your collections and creating a schema out of it.
Mongo compass has a schema tab where you can analyze and use the collection menu to export schema JSON. See below:
You will still need to do a lot of manipulation to create schema out of this JSON, and this JSON isn't meant for creating schema but to understand the kind of data your collection has. e.g. How many docs have this particular field? How many unique values are there for a particular field(cardinality) etc?
Edit 1: I found that the analyzer runs on a subset of docs only not the full collection. We might miss some fields due to that. Read more here

MongoDB Describe Collection

I have a user collection ,I want to see schema for this collection with data type and other detail,which I want to use in mongoosJs while making Schema.
I found a way on internet ,but it is not providing me full detail of collections-below is code for same
var users= db.users.findOne();
for (var key in users) { print (key) ; }
Is there any way to find it.
You can modify your code as per lines below:-
var col_list = db.users.findOne();
for (var col in col_list) {print (typeof col) }
There is no such thing as a schema in mongo. Documents can differ greatly from each other.
So there can be one document where field username is String and another document where field username is Integer.
You could extract the 'schema' from collection by iterating over all documents and collecting schematic information from all of them and then merging that information. But as far as I know there is no direct way in mongo itself.
Edit: a little googling landed me at variety.js, which seems to do what you need.

Field's datatype of collection in mongodb

How to get field information of a collection in mongodb.
information I am looking for are
field name
data type
You will need to loop over all the documents and figure out what the used names are, and which types each specific field uses. MongoDB does not have a schema, so there is no short cut to fetch this. Be also aware that each field's value can have totally different data types as well—another one of MongoDB's strenghts.
To figure out some statistics, such as field names, the following script can help:
mr = db.runCommand({
"mapreduce" : "things",
"map" : function() {
for (var key in this) { emit(key, null); }
},
"reduce" : function(key, stuff) { return null; },
"out": "things" + "_keys"
})
Then run distinct on the resulting collection so as to find all the keys:
db[mr.result].distinct("_id");
But there is no way to also include the field types with a Map/Reduce job like this.
You can't determine the schema of a collection. Each of the objects of an collection might have a different schema, you should be aware of this.
I made a similar question a few months ago , in the post you can find how to retrieve the schema of an object using the java programing language; However, to the best of my knowledge, the is no way to retrieve the data types other than try to cast the objects (this is the way the BasicBsonObjects do it).
MongoDB supports dynamic schema, and there is no inbuilt feature for schema introspection or analysis as at MongoDB 2.4.
However .. it is possible to infer the schema by inspecting using a Map/Reduce across either a sample of documents or the entire collection.
There are a few open source tools which package this approach up in a helpful interface, for example:
Schema.js - extends the mongo shell with collection.schema() prototypes
Variety - runs as a standalone script
I like the approach of schema.js, and include it in my ~/mongorc.js startup file so it is available in my mongo shell sessions.
By default schema.js analyzes up to 50 documents in a collection and returns the results inline. There is a limit option to inspect more (or even all) documents in a collection, and it supports the Map/Reduce out options so results can optionally be saved or merged with an output collection.

How to query username from userId in a collection in Meteor?

I am trying to implement a basic search bar functionality in my app.
I have a bunch of articles, and everyone has an owner. This is specified by the userId in the user parameter of each article.
Right now I can search for keywords within the article, the title, and the date. However I want to be able to query for the username of the author of the article, but I only have the userId available to me...
var keyword = Session.get("search-query");
var query = new RegExp( keyword, 'i' );
var results = Articles.find( { $or: [{'user': query}, // this is only searching userId of the author!
{'title': query},
{'articleText': query},
{'datetime': query}] } );
return {results: results};
I'm not sure how to do this...
Welcome to non-relational databases! You're coming from an RDBMS environment so you expect joins. There are none. Store the username in the article it belongs to, then yes, if a user change their username, you'll need to loop through the collection and update the username where the _id matches.
Please look here for mongo strategies (this isn't Meteor-specific at all): http://docs.mongodb.org/manual/core/data-modeling/
PS: If you get eye haemorrhaging whenever you look at your schema-which-actually-really-isn't-one, you can still give https://github.com/erundook/meteor-publish-with-relations a go - but note that under the hood it's going to get even 'worse' (have a look at your mongo opslog). Publish with relations is only there for convenience and ease of programming, not performance.
Good luck!
So I guess you'd have to either save the username as well as it's own field (or put both id and username in a user object), or search the Users collection for valid usernames, and when you found one use its id to search the Articles DB.
The first suggestion would probably be way more efficient I guess.
That's pretty easy, assuming you're doing the search on the server which has access to all the users:
var username = Meteor.users.findOne(userId).username;

Get a document in MongoDB without specifying collection

MongoDB IDs are unique for a single database cluster. Is it possible to get documents using their IDs, without specifying the collection name?
If yes, how?
If no, why not?
Yes, but not in a scalable way (since you must query each collection). If you have 2 or 3 collections, this might be ok, but... you probably should review your design to figure out why you're doing this. Why are you, by the way?
You get a list of all of the collections in the database.
You loop through them, and query based on _id
Sample shell code:
db.test1.save({});
db.test2.save({});
db.test3.save({});
db.test4.save({});
db.test5.save({});
db.test6.save({});
db.test2.findOne(); // gives: { "_id" : ObjectId("4f62635623809b75e6b8853c") }
db.getCollectionNames().forEach(function(collName) {
var doc = db.getCollection(collName).findOne({"_id" : ObjectId("4f62635623809b75e6b8853c")});
if(doc != null) print(doc._id + " was found in " + collName);
});
gives: 4f62635623809b75e6b8853c was found in test2
ObjectId is designed to be globally unique (worldwide, not just within a single cluster). And it pretty much is.
It includes time, machine id, process id and a random number. However, it does not include database or collection name. Therefore, it is impossible to fetch a document using only the id. You have to provide database and collection names as well.