Mongodb + Scala Insert Subdocuments

668 views
Skip to first unread message

Mike Street

unread,
Mar 31, 2011, 4:02:13 PM3/31/11
to mongodb-user
I am writing a simple scala app to insert a document that has a
subdocument.

I am having issues inserting multiple subdocuments for the same master
document

I am trying to something similar to this

{ author: 'joe',
created : new Date('03/28/2009'),
title : 'Yet another blog post',
text : 'Here is the text...',
tags : [ 'example', 'joe' ],
comments : [ { author: 'jim', comment: 'I disagree' },
{ author: 'nancy', comment: 'Good post' }
]
}

So I can insert the master document and when I add a subdocument it
only adds 1 comment.

Dose anyone have a sample of how you insert multiple subdocuments?

Brendan W. McAdams

unread,
Mar 31, 2011, 4:35:32 PM3/31/11
to mongod...@googlegroups.com
I am making some assumptions here, but I suspect you're trying to set comments with only a single value?

Since comments is an array, you need to use a special syntax to "push" the new comment into it.

Using our Casbah driver for Scala, you could accomplish this as such:


scala> import com.mongodb.casbah.Imports._
import com.mongodb.casbah.Imports._

scala>  val doc = com.mongodb.util.JSON.parse("""{
     | "author" : "joe",
     | "title" : "Yet another blog post",
     | "text" : "Here is the text...",
     | "tags" : [
     | "example",
     | "joe"
     | ],
     | "comments" : [
     | {
     | "author" : "jim",
     | "comment" : "I disagree"
     | },
     | {
     | "author" : "nancy",
     | "comment" : "Good post"
     | }
     | ]
     | }""").asInstanceOf[DBObject]
doc: com.mongodb.casbah.Imports.DBObject = { "author" : "joe" , "title" : "Yet another blog post" , "text" : "Here is the text..." , "tags" : [ "example" , "joe"] , "comments" : [ { "author" : "jim" , "comment" : "I disagree"} , { "author" : "nancy" , "comment" : "Good post"}]}

scala> doc("created") = new java.util.Date()

scala> doc("created")
res6: AnyRef = Thu Mar 31 16:25:22 EDT 2011

// Save the doc to a collection 
scala> val mongo = MongoConnection()("mongodb-user")("scala")
mongo: com.mongodb.casbah.MongoCollection = MongoCollection()

scala> mongo.insert(doc)
res7: com.mongodb.WriteResult = N/A

scala> mongo.findOne()
res8: Option[mongo.T] = Some({ "_id" : { "$oid" : "4d94e366ebac96e4e37e17c8"} , "author" : "joe" , "title" : "Yet another blog post" , "text" : "Here is the text..." , "tags" : [ "example" , "joe"] , "comments" : [ { "author" : "jim" , "comment" : "I disagree"} , { "author" : "nancy" , "comment" : "Good post"}] , "created" : { "$date" : "2011-03-31T20:25:22Z"}})

scala> mongo.head
res0: mongo.T = { "_id" : { "$oid" : "4d94e366ebac96e4e37e17c8"} , "author" : "joe" , "title" : "Yet another blog post" , "text" : "Here is the text..." , "tags" : [ "example" , "joe"] , "comments" : [ { "author" : "jim" , "comment" : "I disagree"} , { "author" : "nancy" , "comment" : "Good post"}] , "created" : { "$date" : "2011-03-31T20:25:22Z"}}

scala>  val id = mongo.head.getAs[ObjectId]("_id").get  
id: com.mongodb.casbah.Imports.ObjectId = 4d94e366ebac96e4e37e17c8

// You could also just read _id from the doc, as it is added as the doc is inserted

// Add extra comments
scala> val updateQ = $push ("comments" -> MongoDBObject("author" -> "brendan", "comment" -> "OMG! Ponies!"))
updateQ: com.mongodb.casbah.commons.Imports.DBObject = { "$push" : { "comments" : { "author" : "brendan" , "comment" : "OMG! Ponies!"}}}

scala> mongo.update(MongoDBObject("_id" -> id), updateQ)                                                    
res2: com.mongodb.WriteResult = N/A

scala> mongo.head.getAs[MongoDBList]("comments")
res12: Option[com.mongodb.casbah.Imports.MongoDBList] = Some([ { "author" : "jim" , "comment" : "I disagree"} , { "author" : "nancy" , "comment" : "Good post"} , { "author" : "brendan" , "comment" : "OMG! Ponies!"}])

Using the $push syntax will add an additional document onto the end of the Array.



--
You received this message because you are subscribed to the Google Groups "mongodb-user" group.
To post to this group, send email to mongod...@googlegroups.com.
To unsubscribe from this group, send email to mongodb-user...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/mongodb-user?hl=en.

Mike Street

unread,
Mar 31, 2011, 4:48:44 PM3/31/11
to mongodb-user
Hmmm well I am not using the Casbah drivers so maybe that is my issue

I am using the following imports
import com.mongodb.Mongo;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.DBCursor;

Thank you for the sample.
I will play around with it some and see if I can get it to work using
the Casbah driver.

Here is my code

val doc = new BasicDBObject()

doc.put("fullname", oSubscriber.fullname)
doc.put("emailaddress", oSubscriber.email)

val docComment = new BasicDBObject()

docComment.put("name", "Mike")
docComment.put("message", "I love it")

doc.put("comment", docComment)
colSub.insert(doc)


This code will insert one master document and one subdocument

Brendan W. McAdams

unread,
Mar 31, 2011, 4:50:51 PM3/31/11
to mongod...@googlegroups.com
Yes, that is your problem.

You are completely replacing the contents of comment with your change.  You'll need to use an atomic update operator add things without rewriting the entire document in your update statement.  See : http://www.mongodb.org/display/DOCS/Updating

Overall if you are working from Scala Casbah will make your life a lot easier --- it wraps the Java driver but provides helpers for common Scala idioms, Scala types and a Query DSL.

Mike Street

unread,
Mar 31, 2011, 4:55:49 PM3/31/11
to mongodb-user
Thank you for the help!

I will look into using the Casbah driver and using the $push function.
Reply all
Reply to author
Forward
0 new messages