Read and update a mongodb document by single call - mongodb

I have a collection called books.
When use browse a particular book, I get the book by id.
But I also want to increase the view count by 1 each time I read the doc.
I can use 2 commands: one to read and another to update the views counter by 1
Is there a wayy to do this by single command like findAndModify?
How to use that using CSharp driver?
Books:
{
{
"_id": "1"
"title" : "Earth Day",
"author" : "John ",
"pages" : 212,
"price" : 14.5,
"views" : 1000
},
{
"_id": "2"
"title" : "The last voyage",
"author" : "Bob",
"pages" : 112,
"price" : 10.5,
"views" : 100
}
}
I have this:
var query = Query.And(Query.EQ("_id", id));
var sortBy = SortBy.Null;
var update = Update.Inc("views", 1);
var result = Books.FindAndModify(query, sortBy, update, true);
But how do I get the matching document back?
EDIT: I got it working..
return result.GetModifiedDocumentAs<T>();
My question is this call GetModifiedDocumentAs() will hit the database again?

No, it won't hit the database again.
When in doubt about things like this, look at the source. It shows that the GetModifiedDocumentAs method just accesses the resulting doc from the existing Response object and casts it to the requested type.

Related

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);

How to get data from a dynamically created Collection in mongoDB

we have a collection say TestColl
having document like
{
"_id" : ObjectId("57558a793f50f61400af205c"),
"title" : "Tile 1",
"addSites" : true,
"version" : 11,
"isMajorVersion" : true
},
{
"_id" : ObjectId("654558a793f50f61400af205c"),
"title" : "Title 2,
"addSites" : false,
"version" : 11,
"isMajorVersion" : true
}
for every documemt of TestColl there is a separete collection in DB
so we have another two collections which is created based upon the object Id of TestColl which is
57558a793f50f61400af205c and 654558a793f50f61400af205c
this makes total three collections.
looking for a way to access a collection '57558a793f50f61400af205c' if my query returns document having _id=654558a793f50f61400af205c in a single query.
Constraint : we need only query without creating any stored procedure or function just pure mongodb query
you can use forEach loop and access data from collection like this:
db.kt.find().forEach(function(doc){
var colName = doc._id.str;
var data = db.getCollection(colName).find().toArray();
printjson(data);
print(","); // to have array of arrays [[],[],[]]
})

Relationship between 2 collections in MongoDB and show data between them

I am making a small database for library with MongoDB. I have 2 collections, first one is called 'books' which stores information about books. The second collection is called 'publishers' which stores information about the publishers and the IDs of the books which they published.
This is the document structure for 'books'. It has 3 documents
{
"_id" : ObjectId("565f2481104871a4a235ba00"),
"book_id" : 1,
"book_name" : "C++",
"book_detail" : "This is details"
},
{
"_id" : ObjectId("565f2492104871a4a235ba01"),
"book_id" : 2,
"book_name" : "JAVA",
"book_detail" : "This is details"
},
{
"_id" : ObjectId("565f24b0104871a4a235ba02"),
"book_id" : 3,
"book_name" : "PHP",
"book_detail" : "This is details"
}
This is the document structure for 'publishers'. It has 1 document.
{
"_id" : ObjectId("565f2411104871a4a235b9ff"),
"pub_id" : 2,
"pub_name" : "Publisher 2",
"pub_details" : "This is publishers details",
"book_id" : [2,3]
}
I want to write a query to show all the details of the books which are published by this publisher. I have written this query but it does not work. When I run it, it displays this message "Script executed successfuly, but there are no results to show.".
db.getCollection('publishers').find({"pub_id" : 2}).forEach(
function (functionName) {
functionName.books = db.books.find( { "book_id": functionName.book_id } ).toArray();
}
)
I think that your data structure is flawed. The publisher is a property of a book, not the other way around. You should add pub_id to each book, and remove book_id from the publisher:
{
"_id" : ObjectId("565f2481104871a4a235ba00"),
"book_id" : 1,
"book_name" : "C++",
"book_detail" : "This is details",
"pub_id" : 1
},
{
"_id" : ObjectId("565f2492104871a4a235ba01"),
"book_id" : 2,
"book_name" : "JAVA",
"book_detail" : "This is details"
"pub_id" : 2
},
{
"_id" : ObjectId("565f24b0104871a4a235ba02"),
"book_id" : 3,
"book_name" : "PHP",
"book_detail" : "This is details"
"pub_id" : 2
}
Then, select your books like such:
db.getCollection('books').find({"pub_id" : 2});
Try this way,
db.getCollection('publishers').find({"pub_id" : "2"}).exec(function(err, publisher){
if (err) {
res.send(err);
}
else
if(publisher)
{
publisher.forEach(function(functionName)
{
functionName.books = db.books.find( { "book_id": functionName.book_id } ).toArray();
})
}
})
I would suggest reading the official documentation, because the relationship between books and publishers is precisely the example which is used there: https://docs.mongodb.org/manual/tutorial/model-referenced-one-to-many-relationships-between-documents/
In mongoDB and noSQL at large, it is not true that publisher must be a property of book. This is only the case in RDBMS, where in one-to-many relationships the reference is in the "one" part. The same works the other way round, books don't have to be a property of publisher. The clue here is in the absence of "must."
It all depends on how many is the "many-to-many". In this case, I'd say it's also about what type of library we're talking about, size of catalogue and whether new book purchases are common:
Is the number of books per publisher small AND data about publisher is often accessed with data about the book? Then, embed publisher info in the book document.
Is the number of books per publisher fairly big but reasonably stable (e.g.: historical library where acquisitions are rare)? Then, create a publishers collection with an array of books per publisher.
Is the number of books per publisher fairly big and catalogue grows at a reasonable pace? Then, include reference in the book document and fetch publisher info with it.
Side note
Although not related to the question, I think your document structure is flawed. _id and book_id are redundant. If you want to follow the RDBMS pattern of incremental integer IDs, then it's absolutely OK that you specify your own _id at the time of inserting the document with 1, 2, 3, etc. ObjectID() is a great thing, but, again, there's no obligation to use it.

How to persist change to mongo in shell?

I've pulled up a document in the mongo shell
car = db.cars.findOne();
...make some changes...
car = db.cars.findOne();
results for same document as if no changes had been made it
There's no save method on a cursor in mongodb. What can I do to persist changes in the shell?
Update. The car document (the first one that's pulled up) has an array of previousdrivers. I have to remove one of the elements and save the doc with it removed.
"previousdrivers" : [
{
"year" : "2011",
"name" : Mr. Zed"
},
{
"year" : "2012",
"name" : "Mr. Bean"
},
{
"year" : "2013",
"name" : "Mr. Smith"
}
]
If you're using the Mongodb shell, you need to use the methods on the collection object to update a document.
For example, if you first:
car = db.cars.findOne();
Then, modify the car instance, you can just use the save method to update the single document (save documentation).
db.cars.save(car);
That will update the single document in the cars collection.
For more advanced usage, you might consider using one of the Array operators which can directly manipulate an array as part of an update.
The findOne() method doesn't return a cursor but a document. You can use any javascript method to manipulate the array. When done, you can call save() for that document. Example
> db.cars.save({make : "ford", gears : [1,2,3,4,5]})
> var doc = db.cars.findOne()
> doc.gears.pop()
5
> db.cars.save(doc)
> db.cars.findOne()
{
"_id" : ObjectId("52239e729a713e4fbc425ed1"),
"make" : "ford",
"gears" : [
1,
2,
3,
4
]
}

Retrieving only the relevant part of a stored document

I'm a newbie with MongoDB, and am trying to store user activity performed on a site. My data is currently structured as:
{ "_id" : ObjectId("4decfb0fc7c6ff7ff77d615e"),
"activity" : [
{
"action" : "added",
"item_name" : "iPhone",
"item_id" : 6140,
},
{
"action" : "added",
"item_name" : "iPad",
"item_id" : 7220,
}
],
"name" : "Smith,
"user_id" : 2
}
If I want to retrieve, for example, all the activity concerning item_id 7220, I would use a query like:
db.find( { "activity.item_id" : 7220 } );
However, this seems to return the entire document, including the record for item 6140.
Can anyone suggest how this might be done correctly? I'm not sure if it's a problem with my query, or with the structure of the data itself.
Many thanks.
You have to wait the following dev: https://jira.mongodb.org/browse/SERVER-828
You can use $slice only if you know insertion order and position of your element.
Standard queries on MongoDb always return all document.
(question also available here: MongoDB query to return only embedded document)