I am aware that MongoDB will dynamically create a collection when you attempt to insert a document into a non-existent collection. My question is:
How do I set up default options so that the collection has the options I want when it is dynamically created?
I don't think you can do that. Your options are:
Pre-create the collections if the pattern is dynamic yet predictable.
List the existing collections before inserting and create the new collection yourself with the right options if it's not already present.
Do not use dynamic collections but rather put the dynamic part as a property to individual documents in a shared collection.
I chose to write a wrapper around mongoc_database_get_collection(). There is a little bit of additional overhead for an extra round trip request to the mongo server to see if the collection already exists. If not, the wrapper creates it with the options I want and returns the new collection. If the collection already exists, the wrapper returns the existing collection.
Related
Is there a way to write a script that updates a document by adding a duplicate field with a different value? I cannot use set as that replaces the existing value. I cannot use push as the field is in an object, not an array. I even tried creating the new field with a different name and renaming it which also replaces the existing field.
You cannot have duplicate fields in a Mongo record. A Mongo collection is a collection of documents, otherwise known as objects. You cannot have a duplicate field in an object and Mongo is no different.
MongoDB (and any other database that I have come across so far) is built around the idea that individual fields are identifiable so they can be filtered by, grouped by, sorted by, etc... That also explains why MongoDB does not provide support for the scenario you're facing. That being said, MongoDB can be used as a dumb datastore for arbitrary JSON data. And the JSON specification does not say anything about duplicate field names which is probably why you can actually store such a document in MongoDB in the first place.
Anyway, there is no way to achieve what you want without loading the entire document, changing it (by adding the duplicate field(s)) and then replacing the whole document. That, however, will work.
I personally cannot think of a reasonable scenario where this sort of document could make sense, though. So I would strongly suggest you revisit your document structure.
I'm trying to build an ionic application which retrieves data from Cloudant using pouchdb. Cloudant allows creating only databases and documents.
How can I create some collections in Cloudant?
Two part answer:
A set of documents that meet certain criteria can be considered a collection in Cloudant/CouchDB. You can create views to fetch those documents. Such a view might check for the existence of a property in a document ("all documents with a property named type"), the value of a property ("all documents with a property named type having the value of book") or any other condition that makes sense for your application and return the appropriate documents.
You basically have to follow a three step process:
determine how you can identify documents in your database that you consider to be part of the collection
create a view based on your findings in the previous step
query the view to retrieve those documents
Above documentation link provides more details.
Properties in your document can represent collections as well, as in the following example, which defines a simple array of strings.
{
"mycollectionname": [
"element1",
"element2",
...
]
}
How you implement collections really depends on your use-case scenario.
Long post, but hope that helps.
I would like to explain this with a RDBMS analogy.
In any RDBMS, a new database would mean a different connection with different set of credentials.
A collection would mean the set of tables in that particular database.
A record would mean a row in a table.
Similarly, you can look at a single Cloudant service instance as a database(RDBMS terminology).
A collection would be a "database" in that service instance in Cloudant's terminology.
A document would correpond to a single row.
Hence, Cloudant has no concept of collection as such. If you need to store your related documents in a separate collection you must do it with multiple databases within the same service instance.
If you want to use only a single database, you could create a field like "record_index" to differentiate between the different documents. While querying these documents, you could use an index. For. e.g. I have a student database. But I do not want to store the records for Arts, Commerce, Science branches in different databases. I will add a field "record_type": "arts", etc. in the records. Create an index,
{ selector: {record_type: "arts"}}
Before doing any operation on the arts records, you can use this index and query the documents. In this way, you will be able to logically group your documents.
What is
Meteor.Collection
and
Meteor.Collection.Cursor
?
How does these two related to each other? Did:
new Meteor.Collection("name")
create a MONGODB collection with the parameter name?
Did new Meteor.Collection("name") create a MONGODB collection with the parameter name?
Not exactly. A Meteor.Collection represents a MongoDB collection that may or may not exist yet, but the actual MongoDB collection isn't actually created until you insert a document.
A Meteor.Collection.Cursor is a reactive data source that represents a changing subset of documents that exist within a MongoDB collection. This subset of documents is specified by the selector and options arguments you pass to the Meteor.Collection.find(selector, options) method. This find() method returns the cursor object. I think the Meteor Docs explain cursors well:
find returns a cursor. It does not immediately access the database or return documents. Cursors provide fetch to return all matching documents, map and forEach to iterate over all matching documents, and observe and observeChanges to register callbacks when the set of matching documents changes.
Collection cursors are not query snapshots. If the database changes between calling Collection.find and fetching the results of the cursor, or while fetching results from the cursor, those changes may or may not appear in the result set.
Cursors are a reactive data source. The first time you retrieve a cursor's documents with fetch, map, or forEach inside a reactive computation (eg, a template or autorun), Meteor will register a dependency on the underlying data. Any change to the collection that changes the documents in a cursor will trigger a recomputation. To disable this behavior, pass {reactive: false} as an option to find.
The reactivity of cursors is important. If I have a cursor object, I can retrieve the current set of documents it represents by calling fetch() on it. If the data changes in between calls, the fetch() method will actually return a different array of documents. Many things in Meteor natively understand the reactivity of cursors. This is why we can return a cursor object from a template helper function:
Template.foo.documents = function() {
return MyCollection.find(); // returns a cursor object, rather than an array of documents
};
Behind the scenes, Meteor's templating system knows to call fetch() on this cursor object. When the server sends the client updates telling it that the collection has changed, the cursor is informed of this change, which causes the template helper to be recomputed, which causes the template to be rerendered.
A Meteor.Collection is an object that you would define like this:
var collection = new Meteor.Collection("collection");
This object then lets you store data in your mongo database. Note just defining a collection this way does not create a collection in your mongo database. The colleciton would be created after you insert a document in.
So in this way you would not have a collection called name until you insert a document to it.
A cursor is the result of a .find() operation:
var cursor = collection.find()
You may have 1000s of documents, the cursor lets you go through them, one by one, without having to load all of them into your server's RAM.
You can then loop through using forEach, or use some of the other operations as specified in the docs : http://docs.meteor.com/#meteor_collection_cursor
A Cursor is also a reactive data source on the client, so if data changes, you can use the same query to update your DOM.
As Neil mentions its also worthwhile knowing Mongo is a NoSQL database. This means you don't have to really create tables/collections. You would just define a collecction like above, then insert a document to it. This way the collection would be created if it didn't exist. If it already existed, it would be inserted into that collection instead.
Browsing your local database
You don't really need to concern yourself with MongoDB until you are publishing your app, you can just interact with it using Meteor alone. In case you want to have a look at what it looks like:
If you want to have a look at your Mongo database. While meteor is running, in the same directory use meteor mongo to bring up a mongo shell, or use a tool like robomongo (Gui tool) to connect to localhost on port 3002 to have a peek at what your mongo database looks like.
I am developing a system where items can be shared with other users via an access key. I'm storing the access keys as fields within a shareinfo object (embedded within the item's document), as shown below:
shareinfo:{
........
<nth key>: <permissions object - may be complex and large>
........
}
When an item is accessed I check shareinfo.key and find if its valid or not.
Currently, to list the keys I am loading (in Java) the entire shareinfo object in memory and running keySet() on it to retrieve and return the keys while the rest of the data is wasted.
Here's the problem: I want to get the list of keys (i.e. object field names) without the accompanying data (because in some cases the permissions object is noticeably large).
I could not find any query in the mongodb docs for such a query. I want to know whether it's possible or not? Or is there an optimized way to load the list of field names into the application without the accompanying field values?
I had the same issue when trying to understand the structure of an existing mongodb database using the mongodb shell. Then I found that I can use the JavaScript function Object.keys() to retrieve an array of the object fields. (Tested with MongoDb 2.4.2)
Object.keys(db.collection.findOne())
MongoDB has a schema-less design, which means that any document could have different fields contained within it from any other document. To get an exhaustive list of all the fields for all the documents, you would need to traverse all the documents in the collection and enumerate each field. For any reasonably sized collection this is going to be an extremely expensive operation.
There are a couple of helpers that make this more simple: Variety and schema.js . They both allow you to limit the documents inspected, and they report on coverage as well. Both amount to doing a map/reduce on the collections, but are at least simpler than having to write one yourself.
If you are just looking for top-level fields across all documents (don't care about sub-fields and all the details statistics provided by variety)
Here is the one-liner
db.things.aggregate([{$project: {arrayofkeyvalue: {$objectToArray: "$$ROOT"}}}, {$unwind:"$arrayofkeyvalue"}, {$group:{_id:null, allkeys:{$addToSet:"$arrayofkeyvalue.k"}}}])
I'd like to code a web app where most of the sections are dependent on the user profile (for example different to-do lists per person etc) and I'd love to use MongoDB. I was thinking of creating about 10 embedabble documents for the main profile document and keep everything related to one user inside his own document.
I don't see a clear way of using foreign keys for mongodb, the only way would be to create a field to_do_id with the type of ObjectId for example, but they would be totally unrelated internally, just happen to have the same Ids I'd have to query for.
Is there a limit on the number of embedded document types inside a top level document that could degrade performance?
How do you guys solve the issue of having a central profile document that most of the documents have to relate to in presenting a view per person?
Do you use semi foreign keys inside MongoDb and have fields with ObjectId types that would have some other document's unique Id instead of embedding them?
I cannot feel what approach should be taken when. Thank you very much!
There is no special limit with respect to performance. The larger the document, though, the longer it takes to transmit over the wire. The whole document is always retrieved.
I do it with references. You can choose between simple manual references and the database DBRef as per this page: http://www.mongodb.org/display/DOCS/Database+References
The link above documents how to have references in a document in a semi-foreign key way. The DBRef might be good for what you are trying to do, but the simple manual reference is very efficient.
I am not sure a general rule of thumb exists for which reference approach is best. Since I use Java or Groovy mostly, I like the fact that I get a DBRef object returned. I can check for this datatype and use that to decide how to handle the reference in a generic way.
So I tend to use a simple manual reference for references to different documents in the same collection, and a DBRef for references across collections.
I hope that helps.