Is there any downside to flatten data model schema in NOSQL Mongodb? - database

I'm using NodeJS and typescript and I'm making typing for my functions in order to get auto-completion.
Currently I have a schema like this for User entity
interface User {
"_id": string
"coach": {
"businessCard": string
}
"firstname": string
}
I'm using a nested object for the coach property, but my question is : What's the point of doing this, behind the scene MongoDB create another object which is referenced in a 1-to-1 relationship.
This probably reduce performances
I'm having issue to type my function to restrict fields that can be targeted in typescript
Let's see with an example :
await this.client.collection<User>('User').findOneAndUpdate(
{ _id: new ObjectID(userId) },
{"coach.businessCard": "50"},
);
will update the nested object.
But this syntax would have worked the same way using
interface User {
"_id": string
"coach.businessCard": string
"firstname": string
}
The difference is that now I can uniformly use one syntax which match the dot notation.
So what could be the advantage of using the first notation I gave compared to the second one which is flatten ?
Best regards

Advantages of using nested Document One-To-One-Relationship are as below:
1. It represents the connection between data fields. For example: to save the user address we need to take multiple fields like:
-> Address line 1
-> Address line 2
-> Locality
-> Region
-> Postcode
-> Building
-> Sub-Building
-> etc.
With the One-To-One-Relation we can bind the related information in a single unit as below:
address: {
Address line 1: String ,
Address line 2: String,
Locality: String,
Region: String,
Postcode: Number,
Building: Number,
Sub-Building: Number,
etc: String
}
2. It is helpful while retrieving such information from the database. For example:
-> To fetch full address details I can project with a single key.
db.collection.find({},{ address: 1} )
-> To fetch specific address field I can project on that as well like below:
db.collection.find({},{ 'address.Locality': 1, 'address.Region': 1} )

Related

How can I search an object of arrays that have no given properties?

I am creating a small app that searches for the row in a .csv file based on a barcode. The objects she has to work with do not have the property:value structure that I normally see. Additionally, each folder has a different set of data, all of which, have these kinds of objects.
Standard (?) Object Structure:
{ name: "Bangladesh", continent: "Asia" },
{ name: "Portugal", continent: "Europe" }
.csv Object:
{ "007B3":"007B3" "A01":"A01" "21018514T1":"21018514T1" }
The first prop:val stays the same for all 96 files, the second and third prop:val pairs are all different.
How can I search for an object using the third prop:val (barcode) pair?
I haven't seen anything online about how to handle this kind of structure. When I console.log() the file, the .csv file looked like a "normal" object, but I don't know how to search these files with objects that look like this. Any help would be appreciated!
If have you have a normal structure in JSON format, it's simple to modify and search
[
{ name: "Bangladesh", continent: "Asia" },
{ name: "Portugal", continent: "Europe" }
]
in your case, the data will look like a JSON structure but is not:
{ "007B3":"007B3" "A01":"A01" "21018514T1":"21018514T1" }
If the structure is not JSON, but still somewhat structured, you can treat it as a string. For this purpose, regular expressions are perfect.
There are different ways to do things on the target string with regular expressions, depending on exact need. It can be split, or captured into elements.
One example is to apply (?:"\w+":"\w+"\s){2}"(\w+)":"(\w+)" which will capture last two elements separately:
$1 ==> 21018514T1
$2 ==> 21018514T1
The regular expression can be modified to specific needs. Example, (?:"\w+":"\w+"\s){2}("\w+":"\w+") which captures $1 ==> "21018514T1":"21018514T1"

Updating Array of Objects in Firebase Realtime Database in React js

I have a problem with updating certain properties of an array of objects in a real-time database in Firebase.
My object looks like the following (see picture).
Now I want to update the IsComing property of the second participant object.
At the moment I use the updateIsComming() function, but this is not very convincing, because I have to rewrite the whole object.
function updateIsComming() {
const db = getDatabase();
update(ref(db, " your_path/EventModel/" + modelkey ), {
Location: "London",
Participants: [
{ Name: "Bella2", IsComming: "true" },
{ Name: "Tom", IsComing: "true" },
],
});
Instead, I just want to reference the specific prop from that array. For example
Participant[1].IsComming = false;
Is there any way I can access a specific array of an object directly.
Arrays as a data structure are not recommended in Firebase Realtime Database. To learn why, I recommend reading Best Practices: Arrays in Firebase.
One of the reasons for this is that you need to read the array to determine the index of the item to update. The pattern is:
Read the array from the database.
Update the necessary item(s) in the array in your application code.
Write the updated array back to the database.
As you already discovered, this is not ideal. As is common on NoSQL databases, consider an alternative data structure that better suits the use-case.
In this case, an alternative data structure to consider is:
Participants: {
"Bella2": true,
"Tom": true
}
In there, we use the name of the participant as the key which means:
Each participant can be present in the object only once, because keys in an object are by definition unique.
You can now update a user's status by their name with: update(db, "your_path/EventModel/" + modelkey + "/Participants/Tom", false).

How to design the user/order/shipping model in mongo for a e-commerce app?

Every order has a shipping info and every user has several shipping addresses. This is my design:
User:
...
defaultAddress: ObjectId
...
Address:
...
...
...
Order:
...
shipping: ObjectId
...
Here are my questions:
Is it reasonable to use a reference for shipping in Order Model, or just embed the entire Address object.
Every time add a new address from App, Is there any better way to check if it is already exist in mongodb?
Should I keep a defaultAddress key in User Model, or should I just use a array to keep all the address object?
Thanks very much.
Addresses bind closely to Users, so make Addresses an array inside Users.
Depending on your overall audit / revisioning data architecture, you may wish to copy the address into the Order doc upon creation to create an unambiguous record of where it went. Having Order reference back into User and address implies you cannot change the address; you would have to mark it as no longer active but not deleted.
Note you do not have to laborious copy all the fields; you can treat the selected address as an object, something like:
var addr = get addr; // from DB or wherever; any shape with any number of subfields is fine.
db.order.insert({orderId:"someID", date:new ISODate(), shippingAddress: addr});
To prevent dupes, it is a matter of looking up the info in the array -- but of course caveats apply such as making sure you canonicalize case, strip white space, remove unnecessary punctuation, etc. etc. Let's assume you have street,city, and state as the matchable fields:
{
"user":"U1",
"addrs": [
{street: "20 Pine Ln", city: "Smallville", state: 'NM'},
{street: "16 Elm Ln", city: "Denver", state: 'CO'},
{street: "77 Sunshine Pkway", city: "Denver", state: 'CO'},
]
}
After grooming the input from app, assume we have a target lookup doc like this. Note: We do NOT have to create the doc with fields in a particular order.
var target = {city: "Denver", state: 'CO', street: '16 Elm Ln'};
The lookup is simple. Since addrs is an array, the match will dive into and iterate over the array. The $elemMatch operator ensures that ALL fields in the candidate match those in the target.
db.foo.aggregate([
{$match: {user:'U1', "addrs":{$elemMatch: target} }}
]);
If no records are found, then this is a new address.

Mongodb query based on item at specific position in array

I want to run a query where an item at a specific position in an array needs to be compared.
For example, consider the GeoJSON format for storing location data.
//sample document from collection user
{
name: "Some name",
location : {
type: "Point",
coordinates : [<Longitude>, <Latitude>]
}
}
How would I query users located at a specific longitude?
I cant seem to find anything in the documentation which can help me do the same.
Queries I have tried:
db.users.find({"location.coordinates[0]" : -73.04303})
Change your query to the following
db.users.find({"location.coordinates.0" : -73.04303})

MongoDB: Query and retrieve objects inside embedded array?

Let's say I have the following document schema in a collection called 'users':
{
name: 'John',
items: [ {}, {}, {}, ... ]
}
The 'items' array contains objects in the following format:
{
item_id: "1234",
name: "some item"
}
Each user can have multiple items embedded in the 'items' array.
Now, I want to be able to fetch an item by an item_id for a given user.
For example, I want to get the item with id "1234" that belong to the user with name "John".
Can I do this with mongoDB? I'd like to utilize its powerful array indexing, but I'm not sure if you can run queries on embedded arrays and return objects from the array instead of the document that contains it.
I know I can fetch users that have a certain item using {users.items.item_id: "1234"}. But I want to fetch the actual item from the array, not the user.
Alternatively, is there maybe a better way to organize this data so that I can easily get what I want? I'm still fairly new to mongodb.
Thanks for any help or advice you can provide.
The question is old, but the response has changed since the time. With MongoDB >= 2.2, you can do :
db.users.find( { name: "John"}, { items: { $elemMatch: { item_id: "1234" } } })
You will have :
{
name: "John",
items:
[
{
item_id: "1234",
name: "some item"
}
]
}
See Documentation of $elemMatch
There are a couple of things to note about this:
1) I find that the hardest thing for folks learning MongoDB is UN-learning the relational thinking that they're used to. Your data model looks to be the right one.
2) Normally, what you do with MongoDB is return the entire document into the client program, and then search for the portion of the document that you want on the client side using your client programming language.
In your example, you'd fetch the entire 'user' document and then iterate through the 'items[]' array on the client side.
3) If you want to return just the 'items[]' array, you can do so by using the 'Field Selection' syntax. See http://www.mongodb.org/display/DOCS/Querying#Querying-FieldSelection for details. Unfortunately, it will return the entire 'items[]' array, and not just one element of the array.
4) There is an existing Jira ticket to add this functionality: it is https://jira.mongodb.org/browse/SERVER-828 SERVER-828. It looks like it's been added to the latest 2.1 (development) branch: that means it will be available for production use when release 2.2 ships.
If this is an embedded array, then you can't retrieve its elements directly. The retrieved document will have form of a user (root document), although not all fields may be filled (depending on your query).
If you want to retrieve just that element, then you have to store it as a separate document in a separate collection. It will have one additional field, user_id (can be part of _id). Then it's trivial to do what you want.
A sample document might look like this:
{
_id: {user_id: ObjectId, item_id: "1234"},
name: "some item"
}
Note that this structure ensures uniqueness of item_id per user (I'm not sure you want this or not).

Resources