MongoDB - $addToSet on a list of Embedded Document - mongodb

I have a list of (mongodb) Embedded Documents within one Document and I am interested in adding a new embedded document to the list of the existing ones.
As far as I have researched, I can use $addToSet, what I can't figure out is how does MongoDB decide if the new document already exists in the list of embedded documents or if it's a new one, i.e. how does MongoDB decide if 2 embedded documents are equal?
p.s. the embedded documents I have are not just values, they are quite complex structures, so I was wondering if there is any place I can define what the equality between 2 of them means...

$addToSet uses the usual mongodb equality rules: it will do a deep value-by-value comparison, so the following two documents are identical:
{ name: "John", hobbies: ["coding", "drinking", "chess"] }
{ hobbies: ["coding", "drinking", "chess"], name: "John" }
(order within documents is not guaranteed, so they are identical)
while those aren't (pairwise):
// compare to:
{ name: "John", hobbies: ["chess", "coding", "drinking"] }
// in arrays, the order matters:
{ name: "John", hobbies: ["coding", "drinking", "chess"] }
// field names and values are case sensitive
{ Name: "John", hobbies: ["chess", "coding", "drinking"] }
{ name: "john", hobbies: ["chess", "coding", "drinking"] }
// additional field:
{ name: "John", lastName: "Doe", hobbies: ["chess", "coding", "drinking"] }
// missing field:
{ name: "John" }
Please note that there is no special field here. You can add an _id field, but it has no special semantics and will be treated just like any other field.

Related

How to search a Mongo collection for a document that contains an array that contains an element that meets a particular criteria?

I'm new at Mongo and there might be a better way to do what I want. I'm dealing with a particular data structure that my application must process.
Suppose that I have a collection that contains two documents that contain information about universities and their student clubs to include the name of each club and the name of each student in each club along with their age:
{
_id: 1, // object ID
name: "Oxford University",
clubs: [{
name: "Soccer",
members: [{
name: "Alice",
age: 22
},
{
name: "Bob",
age: 23
}
]
}, {
name: "Gymnastics",
members: [{
name: "Charlie",
age: 20
},
{
name: "Dorothy",
age: 19
}
]
}]
}
{
_id: 2, // object ID
name: "Cambridge University",
clubs: [{
name: "Chess",
members: [{
name: "Ellen",
age: 30
},
{
name: "Frank",
age: 35
}
]
}, {
name: "Go",
members: [{
name: "Gilbert",
age: 25
},
{
name: "Hikari",
age: 40
}
]
}]
}
Suppose that I want to write a query on this collection that will find universities that have a club that has at least one member aged 40 or older.
How do I do that?
I sketched this example based off of the idea of taking some JSON documents and inserting them into a new collection. Maybe it would be a better idea to break this apart into multiple collections. I just had the idea to research if Mongo might be a good product to use in this situation given that a big part of my job here is to create something that can receive some JSON data, process it, and make it queryable.
MongoDB queries have a convenient feature to query documents that have a specific value or condition in embedded objects and arrays. In the query you can specify the "path" to the object or array using "dot notation" without having to specify the exact array index, etc.
Using your example, you can find the documents where a member of a club is aged 40 or older like this.
db.collection.find({
"clubs.members.age": {
"$gte": 40
}
})
This returns the second document in your example collection.
Try it on mongoplayground.net.

Is there a way to sort the order of columns in mongodb?

I am learning MongoDB and I've encountered a thing that mildly annoys me.
Let's say I got this collection:
[
{
_id: ObjectId("XXXXXXXXXXXXXX"),
name: "Tom",
followers: 10,
active: true
},
{
_id: ObjectId("XXXXXXXXXXXXXX"),
name: "Rob",
followers: 109,
active: true
},
{
_id: ObjectId("XXXXXXXXXXXXXX"),
name: "Jacob",
followers: 2,
active: false
}
]
and I rename the name column to username with the command:
db.getCollection('users').update({}, { $rename: { "name" : "username" }}, false, true)
now the username property is at the end of the record, example:
[
// ... rest of collection has the same structure
{
_id: ObjectId("XXXXXXXXXXXXXX"),
followers: 109,
active: true,
username: "Rob"
}
// ... rest of collection has the same structure
]
How do I prevent this from happening or how do I place them in a specific order? This is infuriating to work with in Robo/Studio 3T. I've got a collection with about 15 columns which are now out of order which in the GUI because of this
The $rename operator logically performs an $unset of both the old name and the new name, and then performs a $set operation with the new name. As such, the operation may not preserve the order of the fields in the document; i.e. the renamed field may move within the document.
Documentation
It is the behaviour from version 2.6
Since it is JSON based, you can get any field easily. And you have very less columns.
Keys in JSON objects are in their very nature unordered. See RFC 4627 which defines JSON, section 1 "Introduction":
An object is an unordered collection of zero or more name/value
pairs, where a name is a string and a value is a string, number,
boolean, null, object, or array.
(Emphasis mine)
Therefore, it would even be correct, if you wrote
{
"name": "Joe",
"city": "New York"
}
and got back
{
"city": "New York",
"name": "Joe"
}

MongoTemplate project Object as List of one Object

I'm using spring MongoTemplate and I have objects like below
The main objects,
{
id: "001",
name: "one",
age: 12,
hobby: "a"
}
{
id: "001",
name: "one",
age: 12,
hobby: "b"
}
The projection result,
{
id: "001",
name: "one",
hobbyList: ["a", "b"]
}
This is the aggregate I'm using so far. It's not working and I don't have an idea how to combine those two objects. How can I fix this?
mongoTemplate.aggregate(newAggregation(project("user.id","user.name")
.and("hobby").as("hobbyList")), "User", User.class).getMappedResults();
You can use group and project operation to achieve this,
First we'll group id, name, age under _id attribute and push all common hobbies to hobbyList attribute.
Then use project is to pull out all the grouped result and exclude _id
newAggregation(
Aggregation.group("id", "name", "age").push("hobby").as("hobbyList"),
Aggregation.project("_id.id", "_id.name", "_id.age", "hobbyList").andExclude("_id")
)

Difference between Reference Mapping and Embedded Mapping

What is the difference between Reference Mapping and Embedded Mapping in Doctrine MongoDB ODM?
I just need to implement one to many relationship.
Embedded documents are stored within the document itself. Referenced documents are stored elsewhere.
A simplified example of how Referenced docs are stored in the db:
//collection one
{
_id: "one_1"
many: [
"many_1",
"many_2",
"many_3"
]
}
//collection many
{
_id: "many_1",
name: "one"
},
{
_id: "many_2",
name: "two"
},
{
_id: "many_3",
name: "three"
}
and Embedded documents:
//collection one
{
_id: "one_1"
many: [
{ _id: "many_1", name: "one"},
{ _id: "many_2", name: "two"},
{ _id: "many_3", name: "three"}
]
}
The former is more flexible, the later is way quicker.
The rule of thumb is to go with references if you need to modify sub-documents individually, or if you need many-to-many refs, or if you can reach the 16MB size limit due to huge number of embedded documents in the foreseeable future.

Mongodb: How to add unique value to each element in array?

I'm a new user of mongodb and I have a model like below. For update list data, I have to specify the element in an array. So I think I need to store a unique value for each element. Because list.name and list.price are variable data.
So are there any good ways to create an unique id in mongodb? Or should I create unique ids by myself?
{
name: 'AAA',
list: [
{name: 'HOGE', price: 10, id: 'XXXXXXXXXX'}, // way to add id
{name: 'FUGA', price: 12, id: 'YYYYYYYYYY'} // way to add id
]
}
Mongodb creates unique id only for documents. There is no better way for list or array elements. So, you should create Unique ids yourself.
Add keep in mind that, While updating your list use $addToSet.
For more information of $addToSet follow this documentation
use ObjectId() on your id field, so like..
db.test.update({name: "AAA"}, { $push: { list: {_id : ObjectId(), name: "dingles", price: 21} }});
reference: https://docs.mongodb.org/v3.0/reference/object-id/
whoever is seeing this in 2022, mongodb creates unique ids automatically we just have to provide schema for that particular array.
like,
_id : {
type: String
},
list: {
type: [{
Name : {
type: String
},
price : {
type: String
}
}]
}
this schema will generate auto id for all elements added into array
but below example will not create it.
_id : {
type: String
},
list: {
type: Array
}