mongodb inbox structure multi addresses - mongodb

I'm going to create an Inbox structure in mongodb. I have some trouble on the Inbox Schema for a multi-user message.
I thought to create something like this where Recipients contains Objects. Every object contains userId and a log to know if the message was red or not.
if it's a correct(efficient!!) structure, how can the user 456 to know if he has some message to read?
{
userId: "123"
,recipients: [ {userId:123, read:true}
,{userId:456, read:false}
,{userId:789, read:false} ]
,text: "message wrote by user 123"
}
,{
userId: "456"
,recipients: [ {userId:123, read:false}
,{userId:456, read:true}
,{userId:789, read:false} ]
,text: "message wrote by user 456"
}

This structure could work provided the CC or To list (I am assuming as being represented by the receipients list) does not grow out of control and becomes unbound.
To answer your initial question, you can use $elemMatch:
db.inbox.find({receipients:{$elemMatch:{userId:456,read:false}}})
That should be an efficient query and will return all messages that user 456 has not yet read.

Related

How to accessing a document with two different keys in Pymongo?

collection = database.collection
collection.insert_one({"_id": friendship_code, "test#gmail.com": "user_name", "second#gmail.com": "second_user_name"}).inserted_id
I wanted to do something like this.Then I would have reached this document in 2 ways.
collection.find_one({"test#gmail.com": "user_name"})
or
collection.find_one({"second#gmail.com": "second_user_name"})
But in the key name "." can't be.
bson.errors.InvalidDocument: key 'test#test.com' must not contain '.'
I can't write the code like this.
collection = database.collection
collection.insert_one({"_id": friendship_code, "user1": "test#gmail.com", "user2": "second#gmail.com"}).inserted_id
Because sometimes mails change places. When a mail is saved with another mail, it can be user1 or user2.
collection = database.collection
collection.insert_one({"_id": friendship_code, "user1": "second#gmail.com", "User2": "another#gmail.com"}).inserted_id
I can check this with the if blog in python but this is not a good approach.
if collection.find_one ({"user1": "second#gmail.com"}) or collection.find_one({"user2": "second#gmail.com"}):
I want to retrieve all "second#gmail.com" data from the collection, even though I don't know if it's user2 or user1.
Instead of storing user1, user2, etc. store them as a users array, then your query is simpler:
collection.insert_one({"_id": friendship_code, "users": ["test#gmail.com", "second#gmail.com"]}).inserted_id
Then either of these queries will return the relevant record:
print(collection.find_one({"users": "test#gmail.com"}))
print(collection.find_one({"users": "second#gmail.com"}))

Mongoose Model.deleteMany() only deletes first element of matches

I'm trying to use the Model.deleteMany() function from mongoose. I'm trying to do something like this:
MyModel.deleteMany({"_id": {$in: ['objectid 1', 'objectid 2'
But this only deletes the first element of the matches from DB (in this case, if 'objectid 1' exists in the DB, it deletes that, but if it isn't nothing happens (both n and deletedCount is 0 in the returned data from the function). I tried using something other than the _id as a query, and this worked. If I had three elements with the same 'name' field, I could delete these.
I tried _id both with and without quotation marks. I also tried converting the object id strings to actual object ids before passing them to deleteMany, but this had no difference either. I have also of course tried to google this, but everything I've found are examples of usage, where it looks like I'm doing the exact same thing as the various blog posts.
I haven't added much code here because I don't really see what else I could be adding. I'm already printing out the input to the $in object, and this is correct. The strangest thing, I think, is that the first element of the list is deleted. Is it treated as a deleteOne request for some reason? are there any config options I need?
As per request, I've added the query and the documents I'd hope to delete:
//Request
MemberModel.deleteMany({"_id": {$in: [
5ee4f6308631dc413c7f04b4,
5ee4f6308631dc413c7f04b5,
5ee4f6308631dc413c7f04b6
]}};
//Expected to be deleted
[
{
"_id": "5ee4f62f8631dc413c7f04b5",
"firstName": "Name",
"lastName": "Nameson",
"__v": 0
},
{
"_id": "5ee4f62f8631dc413c7f04b6",
"firstName": "Other",
"lastName": "Person",
"__v": 0
}
]
If you have any ideas for what I could try, that would be much appreciated.

MongoDB: Designing a db for saving chats / offline / undelivered chats

I am trying to create a mongodb design to support a chat application. The system needs to write the message to a collection with a status of delivered (boolean) and read (boolean).
1 message would be able to be sent to more than 1 person.
Anybody know of a good schema for this type of thing in the mongodb schemaless design?
I was thinking of have a array inside the collection that would contain another document that would have 3 properties.. "name of person addressed to", "read (boolean)" and "delivered (boolean)".
This way at runtime I can reach into the db using dot notation to find all messages addressed to a specific person, all unread messages, all undelivered messsages etc.
I think I need to have another property too "name of person sent from", so i am able to rebuild the a list of messages sent and there status
Has anyone seen a good setup for this ?
Am I thinking this correctly or is there a better way of achieving such a solution
If I understand correctly, you want to keep track of the status of a message. A message is sent by one person, but can be received by many. The status of the message depends on which recipient we're talking about - Joe may have read the message from Tim, while Sally has it in her inbox but hasn't read it, and Joan hasn't received it yet. Based on your rough requirements I would model this with a message_status collection where each document represents the status of one message with respect to one recipient:
{
"message_id" : ObjectId(...) // some unique identifier or reference for the message
"sender" : { "name" : "Tim", "ref" : ObjectId(...) }
"recipient" : { "name" : "Sally", "ref" : ObjectId(...) }
"status" : { "delivered" : true, "read" : false }
}
I'm unclear on to what extent I need to use references versus just embedding in the names because your full use case isn't specified. Getting the kinds of information you mentioned is pretty easy:
all messages addressed to a specific person
db.message_status.find({ "recipient" : ObjectId(...) })
all unread messages [sent to a specific person?]
db.message_status.find({ "recipient" : ObjectId(...), "status.read" : false })
all undelivered messsages [sent to a specific person?]
db.message_status.find({ "recipient" : ObjectId(...), "status.delivered" : false })
rebuild the a list of messages sent and there status
db.message_status.find({ "sender" : ObjectId(...) })

many small documents or less big documents

I have an application with many messages. Every user is able to select one message in order to send this message to an other user. Finally this message will get an flag ('message was send to: user1, user2,...) Those send informations should be stored in mongoDB.
Now I'm thinking about 2 different ways:
1.) many small documents in one collection
Every documents contains the message ID, the user name, who send this message and an Array of recipient, like this:
{
_id:'3DA5FC203,
sender:'username1',
recipient:['user1','user2','user3']
},
{
_id:'4AD290FC,
sender:'username1',
recipient:['user1','user2','user3']
},
{
_id:'4AD290FC,
sender:'usernameX',
recipient:['user2']
}
If 1000 users sends 10 messages a day to 1 ore more recipient, so if have 3.6 millions documents per year.
2.) less bigger documents in one collection
The other way would be less documents, but bigger one. For example one document for every message with the information about all the sender and recipient of this message. An mongoDB entry could look like that:
{
_id:'3DA5FC203,
'username1':['user1','user2','user3'],
},
{
_id:'4AD290FC,
'username1':['user1','user2','user3'],
'usernameX'['user2']
},
In this case: only 2 documents instead of 3 (example above), but one document could contain 100 or more sender.
So my question: which case will mongoDB handle better? Many small documents or less big? And which scenario is better for performing analyses, like: show all messages and recipient from one sender (username1)?
Using keys as values, like you do in:
'username1':['user1','user2','user3'],
is a bad idea as you can not do a indexed query where you look for documents that have a specific sender. This works:
db.messages.find( { 'username1' : { $exists: true } } );
But it is not going to be fast.
It is probably wise to keep your first option, with one document per message and sender.
Then you can just do:
db.messages.find( { sender: 'username1' } );
Adding a new recipient to this document can be done with:
db.messages.update(
{ 'msgid' : '867896', sender: "username1" },
{ 'recipient': { $push: "user4" } }
);
You can make MongoDB use the same index for both queries as well, by having:
db.messages.ensureIndex( { sender: 1, msgid: 1 } );
Other hints
You need to be aware that you also can not have two documents with the same _id value as you have in your first example. So you will have to make sure to add this ID as a different field than _id. For example:
{
msgid:'3DA5FC203,
sender:'username1',
recipient:['user1','user2','user3']
},
And let MongoDB just create the _id field for you.

Mongo DB Design For Events Calendar

We have an events calendar and here is what I am thinking for our basic mongo schema:
users
username
password
salt
events
name
description
tags[]
category
venue_id
...
venues
name
address
loc
Queries that will be done are:
Listing of distinct tags (this might be hard given current design)
events in a given tag
Event information along with the venue location
All event and venue information for a particular event
All events near me. Need to use a geo index on loc
Any feedback/ideas on if we should be nesting venues inside events or use mysql instead?
Ok, that looks pretty good. Let's construct some of the queries.
Assuming the collections are named users, events, venues:
Insert some dummy events:
db.events.insert({tags:["awesome","fun","cool"]})
db.events.insert({tags:["sweet","fun","rad"]})
Make an index (like a boss)
db.events.ensureIndex({ tags: 1 })
Listing of distinct tags (this might be hard given current design):
Nope, not hard.
db.events.distinct("tags")
[ "awesome", "cool", "fun", "rad", "sweet" ]
Events in a given tag (you meant "with a given tag" right?)
db.events.find({tags: "fun"})
{ "_id" : ObjectId("4ecc08c62477605df6522c97"), "tags" : [ "awesome", "fun", "cool" ] }
{ "_id" : ObjectId("4ecc08d92477605df6522c98"), "tags" : [ "sweet", "fun", "rad" ] }
Event information along with venue location
You can do this a couple different ways. One way would be to query for the event and subsequently query for the venue. With both documents, join (combine) the data you want manually.
OR
You can denormalize a bit and store cached venue names + locations (but not venue details like hours of operation, max occupancy, website, phone number, etc..) for a speed boost (1 query instead of 2) That method comes with the standard denormalization caveat of not being able to update your data in one place.
All event and venue information for a particular event
See above
All events near me. Need to use a geo index on loc
Two queries again, same concept as above just reverse the order.
Get the venues:
db.venues.find( { loc : { $near : [lat,lon] } } )
Get the events using the venue ids:
db.events.find( { venue : { $in : [id1,id2,id3...] } } )
Some of this stuff can be done automatically for you if you use an ODM.
Good luck!