Insert new record using Scala Salat/Casbah and Mongodb - mongodb

Greetings,
I am using Salat and Casbah to create a user collection in Mongodb, everything works great until I added a unique index on the email field. Now my insert returns a unique id with no actual record added in the DB for existing email addresses. I am new to scala and Casbah/Salat so I apologize if I am asking an obvious question.
here are my collection indexes
db.users.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "study_test.users"
},
{
"v" : 1,
"unique" : true,
"key" : {
"email" : 1
},
"name" : "users_email",
"ns" : "study_test.users"
}
]
and this is my dao object
object UserDao extends SalatDAO[UserModel, ObjectId](collection = MongoUtil.getCollection("study", "users")) {
val logger = LoggerFactory.getLogger(UserDao.getClass)
val dao = this
UserDao.collection.ensureIndex(DBObject("email" -> 1), "users_email", true)
RegisterJodaTimeConversionHelpers()
def create(userContract: UserContract): Option[ObjectId] = {
val userModel = UserConverter.toModel(userContract)
dao.insert(userModel)
}
}

I found what the problem was, I upgraded mongodb and casbah 2.10 but used MongoConnection to connect to mongoDB. I switched to connection using mongo client and all works as expected.

What do you mean by "Now my insert returns a unique id with no actual record added in the DB for existing email addresses." Can you specify an example?
Since you have a unique index, insert will fail for a new insert (or whatever the behaviour for scala/casbah is) for the same email id.

Related

MongoDB WildCard query taking too much time using Grails

MongoDB v4.0.2
Grails 3.3.5
I've more than 20 Millions of records stored in a collection. I'm trying to wildcard search in that collection like as follows...
def personList = Person.collection.find(['vehicleNumber': ['$regex':/.*GJ18AD.*/] ]).sort(["datetime":-1])
Index on Person Collection
db.person.getIndexes()
{
"v" : 2,
"key" : {
"vehicleNumber" : 1
},
"name" : "vehicleNumber_1",
"ns" : "analytics.person",
"weights" : {
"numberPlate" : 1
},
"default_language" : "english",
"language_override" : "language",
"textIndexVersion" : 3
}
Is there any other way for the wildcard search?
There is no changes required in the indexing. But the minor change in the filter Object which I'm passing to the collection.
Previously, I was using following filter object syntax:
def personList = Person.collection.find(['vehicleNumber': ['$regex':/.*GJ18AD.*/] ]).sort(['datetime':-1])
Then I've change only the regex in the above syntax:
def personList = Person.collection.find(['vehicleNumber': ['$regex':'.*GJ18AD.*'] ]).sort(['datetime':-1])
It's works for me in the MongoDB version 4.2.1.

Mongo db query where condition for a column (list of values) having a value

I am trying to find a way to filter the records in Mongo db using Spring query.
Here is the scenario, let's see I have an Activity entity/document. One of the fields is a list of names. I want to see if I can get all the records that the names field includes get given value, let's say "Joker".
For example, my json in Mongo is
Activity 1 -
{
"_id" : ObjectId("52c14eb92f7ceb854e445354"),
...
"names" : [{
"username" : "username1",
"realname" : "Super Man"
}, {
"username" : "username2",
"realname" : "Iron Man"
}]
}
Activity 2 -
{
"_id" : ObjectId("52c14eb92f7ceb854e445355"),
...
"names" : [{
"username" : "username3",
"realname" : "Bat Man"
}, {
"username" : "username4",
"realname" : "Joker"
}]
}
And I expect the query will let me get Activity 2 only.
Also, if possible, I prefer to use spring Mongo query in my code. Thanks in advance.
Try
db.collection.find({"names.realname": "Joker"});
I never used Spring query but should be something like
Query query = new Query();
query.addCriteria(Criteria.where("names.realname").is("Joker"));
List<MyClass> users = mongoTemplate.find(query, MyClass.class);

Zipping two collections in mongoDB

Not a question about joins in mongoDB
I have two collections in mongoDB, which do not have a common field and which I would like to apply a zip function to (like in Python, Haskell). Both collections have the same number of documents.
For example:
Let's say one collection (Users) is for users, and the other (Codes) is of unique randomly generated codes.
Collection Users:
{ "_id" : ObjectId(""), "userId" : "123"}
{ "_id" : ObjectId(""), "userId" : "456"}
Collection Codes:
{ "_id" : ObjectId(""), "code" : "randomCode1"}
{ "_id" : ObjectId(""), "code" : "randomCode2"}
The desired output would to assign a user to a unique code. As follows:
Output
{ "_id" : ObjectId(""), "code" : "randomCode1", "userId" : "123"}
{ "_id" : ObjectId(""), "code" : "randomCode2", "userId" : "456"}
Is there any way of doing this with the aggregation pipeline?
Or perhaps with map reduce? Don't think so because it only works on one collection.
I've considered inserting another random id into both collections for each document pair, and then using $lookup with this new id, but this seems like an overkill. Also the alternative would be to export and use Python, since there aren't so many documents, but again I feel like there should be a better way.
I would do something like this to get the records from collection 1 & 2 and merge the required fields into single object.
You have already confirmed that number of records in collection 1 and 2 are same.
The below code will loop through the cursor and map the required fields into one object. Finally, you can print the object to console or insert into another new collection (commented the insert).
var usersCursor = db.users.find( { } );
var codesCursor = db.codes.find( { } );
while (usersCursor.hasNext() && codesCursor.hasNext()) {
var user = usersCursor.next();
var code = codesCursor.next();
var outputObj = {};
outputObj ["_id"] = new ObjectId();
outputObj ["userId"] = user["userId"];
outputObj ["code"] = code["code"];
printjson( outputObj);
//db.collectionName.insertOne(outputObj);
}
Output:-
{
"_id" : ObjectId("58348512ba41f1f22e600c74"),
"userId" : "123",
"code" : "randomCode1"
}
{
"_id" : ObjectId("58348512ba41f1f22e600c75"),
"userId" : "456",
"code" : "randomCode2"
}
Unlike relational database in MongoDB you doing JOIN stuff at the app level (so it will be easy to horizontal scale the database). You need to do that in the app level.

Insert nested document using Reactivemongo, Play framework and Scala

I am new to Play framework 2.3 using scala and reactivemongo. I have already developed few pages to load data from forms into mongodb.
So far so good. But now I’m planning to use nested document feature of mongodb as there is no direct support for JOINS in mongodb. I am aware of manual reference and DB refs way joining collections in MongoDB.
There are some questions posted on this forum related to nested documents in mongodb but they are of no help to me.
I would really appreciate if you can show me, how to insert and update sub-documents in the already existing document in mongodb collection using play framework, scala and reactivemongo?
The structure of the data is as follows:
"_id" : ObjectId("5516ae699aaebdfc0bc47f7d"),
"name" : "ABCD",
"address" : "Blue Skies",
"dob" : 135962900000,
"email" : ""
And I would like to add new sub-document entries as follows:
"_id" : ObjectId("5516ae699aaebdfc0bc47f7d"),
"name" : "ABCD",
"address" : "Blue Skies",
"dob" : 01/01/1970,
"email" : "",
“visits” : [
{
“date” : 18/02/2015,
“comments” : “Some comments”,
“createdBy” : “XYZ”
},
{
“date” : 23/03/2015,
“comments” : “Some comments”,
“createdBy” : “PQR”
}
]
Here’s how my code for updating a document in a collection looks like:
def updateData(id: String) = Action.async { implicit request =>
projectForm.bindFromRequest.fold(
formWithErrors => Future.successful(BadRequest(html.editProject(id, formWithErrors))),
project => {
val futureUpdateProj = collection.update(Json.obj("_id" -> Json.obj("$oid" -> id)), project.copy(_id = BSONObjectID(id)))
futureUpdateProj.map { result =>
projectsHome.flashing("success" -> s"Project ${project.name} has been updated")
}.recover {
case t: TimeoutException =>
Logger.error("Problem found in Project update process")
InternalServerError(t.getMessage)
}
})
}

Query returning null - Using Java Driver for Mongo

I am trying to update a collection by querying the id of the collection, but for some reason I am not able to update the collection at all. What am I doing wrong?
DBCollection collection = db.getCollection("sv_office_src");
for(OutputSet o : outputData) {
BasicDBObject searchOfficeQuery = new BasicDBObject();
searchOfficeQuery.append("_id", o.getId());
//collection.findOne(searchOfficeQuery);
System.out.println(searchOfficeQuery);
BasicDBObject newUpdateDocument = new BasicDBObject();
newUpdateDocument.append("target_key", o.getTarget_key());
newUpdateDocument.append("target_office_id", o.getTarget_office_id());
newUpdateDocument.append("target_firm_id", o.getTarget_firm_id());
newUpdateDocument.append("score", o.getScore());
BasicDBObject updatedDocument = new BasicDBObject();
updatedDocument.append("$set", newUpdateDocument);
collection.update(searchOfficeQuery, updatedDocument);
System.out.println("Output : " + updatedDocument);
}
and the output is as follows:
{ "_id" : "52c6f6d5250c7ef0f654c7dd"}
Output :
{ "$set" : { "target_key" : "440786|PO BOX 15007|||WILMINGTON|US-NC|28408-5007|US" , "target_office_id" : "503677" , "target_firm_id" : "87277" , "score" : "17"}}
So I am getting the right document, but in the mongo shell when I am doing the following, you will see that the updated columns are blank.
I know the key Firm_Name for the above id.
> db.sv_office_src.find ({Firm_Name: "1717 Capital Management Company"})
{ "_id" : ObjectId("52c77b8d250ca11d792200aa"), "Firm_Name" : "1717 Capital Management Company", "Firm_Id" : "6715", "Office_Id" : "200968", "Office_Address_Line_1" : "PO BOX 15626", "Office_Address_Line_2"
: "", "Office_Address_Line_3" : "", "Office_City" : "WILMINGTON", "Office_Region_Ref_Code" : "US-DE", "Office_Postal_Code" : "19850-5626", "Office_Country_Ref_Code" : "US", "src_key" : "200968|PO BOX 15626||
|WILMINGTON|US-DE|19850-5626|US", "target_key" : "", "target_office_id" : "", "target_firm_id" : "", "target_firm_name" : "", "score" : "" }
The id's for the two documents are not the same:
{ "_id" : "52c6f6d5250c7ef0f654c7dd"}
vs.
{ "_id" : ObjectId("52c77b8d250ca11d792200aa") <snip/>
Two issue here. The hex values are different and the type of the first one looks to be a "string" and the type if the second is ObjectId.
If your OutputSet.getId() method is returning the hex string then you can convert it to an ObjectId (http://api.mongodb.org/java/current/org/bson/types/ObjectId.html) by passing it to the constructor:
searchOfficeQuery.append("_id", new ObjectId( o.getId() ) );
You can also inspect the WriteResult (http://api.mongodb.org/java/current/com/mongodb/WriteResult.html) from the update command to see how many documents each update updated. Look at the WriteResult.getN() method. In this case I would expect it to be 1 if it finds the document and updates it, zero if it does not find the document.
HTH,
Rob.
The _id in your searchOfficeQuery and the _id in your "proof" from your Firm_Name query don't match. You might try
db.sv_office_src.find({ "_id" : ObjectId("52c6f6d5250c7ef0f654c7dd")})
to see the document that you actually $set all those fields in.