Limit inserts in mongodb - mongodb

I enter these documents in a table:
db.RoomUsers.insert( {userId: 1, roomId: 1} )
db.RoomUsers.insert( {userId: 2, roomId: 1} )
db.RoomUsers.insert( {userId: 3, roomId: 1} )
db.RoomUsers.insert( {userId: 4, roomId: 1} )
Now, my application requires that in RoomUsers there can be a limited number of user in each room. Let's say that there cannot be more than 5 user for each room.
How to fix that?
If I was using an RDBM I could maybe have this strategy(Im not sure its the best one, but still):
1 - Count number of entries in RoomUsers where roomId = X
2 - If number of users is less than Y then:
2A - Start a transaction
2B - Insert new user in RoomUsers
2C - Count number of entries in RoomUsers where roomId = X
2D - If number of users is greater than Y then: Rollback. Otherwise: commit
MongoDB doesn't really have transaction, what I understand. How to accomplish the same thing in noSql?

There is one approach will let you do it atomically.
You should embed userIds into RoomUsers collection. Something like
{ "userIds" : [ 1, 2, 3, 4 ], "roomId" : 1 }
Now you can use the below update query.
db.RoomUsers.update( { roomId : 1, "userIds": { $not: {$size: 5 } } }, { $push : { "userIds":5 } } )

Related

MongoDB - Filter on First Field of a Two Field Compound Index and Sort on the Second Field?

I am inserting data into my MongoDB collection of the following format.
{'customer_id': 1, 'timestamp': 200}
{'customer_id': 2, 'timestamp': 210}
{'customer_id': 3, 'timestamp': 300}
I have a compound index created with keys: { 'customer_id': 1, 'timestamp': -1 }
db.collection.createIndex( { customer_id: 1, timestamp: -1 } , { name: "query for inventory" } )
Now, I need to filter such that I get the documents with customer_id = 1 or 2 and then sort the documents on the timestamp (in descending format, that is the latest will be at the top).
My query looks like this:
db.collection.find( { 'customer_id': { '$in': [ 1, 2 ] } } ).sort( { 'timestamp': -1 } ).limit( 100 )
I know how to do the query but I am unsure if I should be using this Compound Index or using two Indices on the separate fields or both.
It would be really helpful if I could get a clarification on which approach to use and why that approach is better.

MongoDB compound index order of the fields

I have collection schema
1) user
2) age
3) role
I have created compound index ( { age: 1, user: 1 } ). When I find documents with criteria { age: { $gt: 21, $lt: 50 }, user: 'user124' }, the index is properly used ( I am watching in explain()), but when I change order to { user: '124', age: { $gt: 21, $lt: 50 } } results and index usage is identical. When I have compound index on two fields, order in criteria doesn't matter?
This is correct, the order does not matter.
In fact, only arrays in the query are ordered and dictionarys are not.
http://json.org/

How mongo index intersection works

If I create two indexes, one with descending and one with ascending with time, if I query old and new data do I get to search in both the indexes and I get a good performance in both the cases.
Currently I have index in descending so when I query old data it is coming really really slow. I am thinking of creating one more ascending and try it out. Since I have a huge number of documents (32 million) I thought of asking here first.
This is my index and the query which cause me issue when start/end time is bit old. I have a TTL close to 100 days which make my collection to keep 32 million documents.
index: {
"source_type" : 1.0 ,
"source_id" : 1.0 ,
"key" : 1.0 ,
"start" : -1.0 ,
"end" : -1.0
}
query: keys = diag_db.telemetry_series.aggregate([
{ '$match': {
'source_type': 'SERVER',
'start': { '$gte': start },
'end': { '$lte': end },
'$or': stream_id_query
}},
{ '$project': {
'source_id': 1,
'key': 1
}},
{ '$group':
{ '_id': { 'source': '$source_id', 'key': '$key' }
}}
])['result']

MongoDB update outter and array-embedded document atomically

I have an object in the cart collection:
{
_id: 1,
purchased: 0,
items: [
{
item_id: 5,
count: 0
},
{
item_id: 6,
count: 0
},
]
}
And I would like to atomically increment both purchased and count of item_id: 6. I believe the correct update command is:
db.carts.update({_id: 1, "items.item_id": 6},
{
$inc: {
purchased: 1
"items.$.count": 1
}
})
This seems to work in the console but I am not sure if this is 100% correct. Can anyone spot any issues with this update command or confirm this is correct for my use case?
For scaling this to my app, suppose _id is an ObjectId and item_id is also ObjectId (ie they are unique).

Conditional $inc in a nested MongoDB array

My database looks like this:
{
_id: 1,
values: [ 1, 2, 3, 4, 5 ]
},
{
_id: 2,
values: [ 2, 4, 6, 8, 10 ]
}, ...
I'd like to update every value in every document's nested array ("values") that meets some criterion. For instance, I'd like to increment every value that's >= 4 by one, which ought to yield:
{
_id: 1,
values: [ 1, 2, 3, 5, 6 ]
},
{
_id: 2,
values: [ 2, 5, 7, 8, 11 ]
}, ...
I'm used to working with SQL, where the nested array would be a seperated table connected with a unique ID. I'm a little lost in this new NoSQL world.
Thank you kindly,
This sort of update is not really possible using nested arrays, the reason for this is given in the positional $ operator documentation, and that states that you can only match the first array element for a given condition in the query.
So a statement like this:
db.collection.update(
{ "values": { "$gte": 4 } },
{ "$inc": { "values.$": 1 } }
)
Will not work in the sense that only the "first" array element that was matched would be incremented. So on your first document you would get this:
{ "_id" : 1, "values" : [ 1, 2, 3, 6, 6 ] }
In order to update the values as you are suggesting you would need to iterate the documents and the array elements to produce the result:
db.collecction.find({ "values": { "$gte": 4 } }).forEach(function(doc) {
for ( var i=0; i < doc.values.length; i++ ) {
if ( doc.values[i] >= 4 ) {
doc.values[i]++;
}
}
db.collection.update(
{ "_id": doc._id },
{ "$set": { "values": doc.values } }
);
})
Or whatever code equivalent of that basic concept.
Generally speaking, this sort of update does not lend itself well to a structure that contains elements in an array. If that is really your need, then the elements are better off listed within a separate collection.
Then again, the presentation of this question is more of a "hypothetical" situation without understanding your actual use case for performing this sort of udpate. So if you possibly described what you actually need to do and how your data really looks in another question, then that might get a more meaningful response in terms of the best approach for you to use.