How to update a one to many relationship MongoDB - mongodb

If i have a Person collection that has many addresses, how can I insert multiple addresses that belong to a person? I know how to do it if it were a one to one relationship where I would simply do something like:
db.persons.update({_id: '12345'}, {$set: {'address': '12345 fake st'}})
However, that won't work for a one to many relationship since the person's address would get replaced every time someone adds an address to that person. Can someone help? Thank you in advance.

If you want a person to hold many addresses then you could make address an array and you could insert new addresses using the push operator.
db.persons.update(
{ "_id": "12345" },
{ "$push": { "address": "12345 fake st"}}
);
Your schema would then look like this:
{
"_id" : "12345",
"address" : [
"12345 fake st",
"6789 second st",
...
]
}
Of course you can make this as complex as required. So if you need to store extra information for each address, you can instead insert subdocuments into the address array.
{
"_id" : "12345",
"address" : [
{
"number" : "6789",
"street" : "second st",
"primary" : false
},
{
"number" : "12345",
"street" : "fake st",
"primary" : true
},
...
]
}
As noted in the comments, if you want to ensure that there are no duplicates in your array, you should use the $addToSet operator, which provides that functionality.

Related

How can find a record based on array object key-value in mongodb?

I have a record in database:
{
"name" : "user",
"number":"09xxxxxxx21",
"pc" : [{
"pcId" : "1",
"pcName" : "Desktop",
"pcOwner" : "user1"
}, {
"pcId" : "2",
"pcName" : "Laptop",
"pcOwner" : "user1"
}
]}
}
Using mongo find query I'm able to get record when giving name but I want to fetch record based on pcId.
I think you were looking for something like this.
https://mongoplayground.net/p/LsUCVSj_7_e
db.collection.find({
"pc.pcId": "12"
})
This works perfect.
Try this one:
db.collection.find({"pc.pcId": "2"})
As pcId is the child element of pc you need to refer to the parent first to reach that element.
for reference: https://mongoplayground.net/p/uWD9tPPhupR

mongodb how to display Null or none for a field instead of it being blank

The query below will show me the names of people and all their details. Some have addresses, some have not. It shows the addresses where they exist. What do I use if I wanted to show "addresses: "none" " where there are none given? I am also trying to sort by name.
db.test.find({name:{$exists:true}}, {_id:0}, {$sort:{"name":1}})
So far I can select the ones which have names, hide the _id column from view and sort by name. All the addresses (where they exist) are given. It is the "addresses: none" I am finding tricky.
Any pointers? Thank you.
test collection with the following documents
{"_id" : 1, "name" : "Thyame", "address": "Kapan" },
{"_id" : 2, "name" : "Diple", "address": null },
{"_id" : 3, "name" : "Sid" }
and Query is
db.test.aggregate
(
[
{
$project: {
address: { $ifNull: [ "$address", "Null" ] }
}
}
]
);

Adding multiple key/values

In my database.collection i.e. db.blog.posts I am trying to add a key and value that itself has multiple keys and values.
Current collection:
db.blog.posts.findOne()
"title":"blog posts"
I tried using $set, $push but nothing seems to work.
This also didn't work when I tried adding single collection:
db.blog.posts.updateOne({"title":"blog posts"}, {"$set":{"comments":[{"comment":"good post", "author":"john","votes":0}]}})
Nor insertOne instead of updateOne and I even tried with:
var myEmployee=[
{"comment":"good post", "author":"john", "votes":0},
{"comment":"i thought it was too short", "author":"claire","votes":3},
{"comment":"free watches", "author":"claire","votes":-1},
];
db.blog.posts.insert(myEmployee)
This is what I want:
"title" : "A blog post",
"comments" : [
{
"name" : "joe",
"email" : "joe#example.com",
"content" : "nice post."
},
{
"name" : "bob",
"email" : "bob#example.com",
"content" : "good post."
}
]
The updateOne command you have should have created an array for comments with a single entry. If you wanted multiple entries, you can just add multiple objects to the array in the update. The $set operator will change the value of the key to what you set as the second parameter.
db['blog.posts'].updateOne({"title":"blog posts"}, {
"$set": {
"comments":[
{
"name" : "joe",
"email" : "joe#example.com",
"content" : "nice post."
},
{
"name" : "bob",
"email" : "bob#example.com",
"content" : "good post."
}
]
}
})
If you want to add additional items to the comments, this can be done with $push. The $push operator adds to the array.
db['blog.posts'].updateOne({"title":"blog posts"}, {
"$push": {
"comments": {
"comment": "good post",
"author": "john",
"votes": 0
}
}
})
Docs for $set
Docs for $push
NB the examples above are for a collection named 'blog.posts' rather than a database named 'blog' and a collection names 'posts'. Ideally, brackets should be used for the property accessor where the collection name is not a valid JavaScript identifier although the dot notation in the question still works.

MongoDB: insert embedded document directly from another collection

I have two collection:
// Profile
{
_id: "12345",
name: "max",
country: "IT"
}
// Association
{
_id: "43234",
idclub: "1000",
state: "0"
}
I want to insert a Profile on Association without searching it.
In my code i search for an Association but i don't have the object Profile in that moment, i just have its "id".
Is it possible to perform some kind of insert on collection A retrieving on the fly the object of collection B given it's own ID?
And then, is this a recurring practice? As i can find nothing it seems not properly the best way...
Thanks
Use findAndModify operator
db.createCollection("Association");
db.Association.insert({ _id : "43234", idclub:"1000",state:"0"});
db.Association.findAndModify({
query:{ _id:"43234" },
update:{ $set:{ "profile":{ _id:"12345","name":"max","country":"IT" } } }
});
db.Association.find();
{"_id" : "43234", "idclub" : "1000", "state" : "0", "profile" : { "_id" :
"12345", "name" : "max", "country" : "IT" } }

Suitability of MongoDB for hierarchial type queries

I have a particular data manipulation requirement that I have worked out how to do in SQL Server and PostgreSQL. However, I'm not too happy with the speed, so I am investigating MongoDB.
The best way to describe the query is as follows. Picture the hierarchical data of the USA: Country, State, County, City. Let's say a particular vendor can service the whole of California. Another can perhaps service only Los Angeles. There are potentially hundreds of thousands of vendors and they all can service from some point(s) in this hierarchy down. I am not confusing this with Geo - I am using this to illustrate the need.
Using recursive queries, it is quite simple to get a list of all vendors who could service a particular user. If he were in say Pasadena, Los Angeles, California, we would walk up the hierarchy to get the applicable IDs, then query back down to find the vendors.
I know this can be optimized. Again, this is just a simple query example.
I know MongoDB is a document store. That suits other needs I have very well. The question is how well suited is it to the query type I describe? (I know it doesn't have joins - those are simulated).
I get that this is a "how long is a piece of string" question. I just want to know if anyone has any experience with MongoDB doing this sort of thing. It could take me quite some time to go from 0 to tested, and I'm looking to save time if MongoDB is not suited to this.
EXAMPLE
A local movie store "A" can supply Blu-Rays in Springfield. A chain store "B" with state-wide distribution can supply Blu-Rays to all of IL. And a download-on-demand store "C" can supply to all of the US.
If we wanted to get all applicable movie suppliers for Springfield, IL, the answer would be [A, B, C].
In other words, there are numerous vendors attached at differing levels on the hierarchy.
I realize this question was asked nearly a year ago, but since then MongoDB has an officially supported solution for this problem, and I just used their solution. Refer to their documentation here: https://docs.mongodb.com/manual/tutorial/model-tree-structures-with-materialized-paths/
The concept relating closest to your question is named "partial path."
While it may feel a bit heavy to embed ancestor data; this approach is the most suitable way to solve your problem in MongoDB. The only pitfall to this, that I've experienced so far, is that if you're storing all of this in a single document you can hit the, as of this time, 16MB document size limit when working with enough data (although, I can only see this happening if you're using this structure to track user referrals [which could reach millions] rather than US cities [which is upwards of 26,000 according to the latest US Census]).
References:
http://www.mongodb.org/display/DOCS/Schema+Design
http://www.census.gov/geo/www/gazetteer/places2k.html
Modifications:
Replaced link: http://www.mongodb.org/display/DOCS/Trees+in+MongoDB
Note that this question was also asked on the google group. See http://groups.google.com/group/mongodb-user/browse_thread/thread/5cd5edd549813148 for that disucssion.
One option is to use an array key. You can store the hierarchy as an
array of values (for example ['US','CA','Los Angeles']). Then you can
query against records based on individual elements in that array key
For example:
First, store some documents with the array value representing the
hierarchy
> db.hierarchical.save({ location: ['US','CA','LA'], name: 'foo'} )
> db.hierarchical.save({ location: ['US','CA','SF'], name: 'bar'} )
> db.hierarchical.save({ location: ['US','MA','BOS'], name: 'baz'} )
Make sure we have an index on the location field so we can perform
fast queries against its values
> db.hierarchical.ensureIndex({'location':1})
Find all records in California
> db.hierarchical.find({location: 'CA'})
{ "_id" : ObjectId("4d9f69cbf88aea89d1492c55"), "location" : [ "US", "CA", "LA" ], "name" : "foo" }
{ "_id" : ObjectId("4d9f69dcf88aea89d1492c56"), "location" : [ "US", "CA", "SF" ], "name" : "bar" }
Find all records in Massachusetts
> db.hierarchical.find({location: 'MA'})
{ "_id" : ObjectId("4d9f6a21f88aea89d1492c5a"), "location" : [ "US", "MA", "BOS" ], "name" : "baz" }
Find all records in the US
> db.hierarchical.find({location: 'US'})
{ "_id" : ObjectId("4d9f69cbf88aea89d1492c55"), "location" : [ "US", "CA", "LA" ], "name" : "foo" }
{ "_id" : ObjectId("4d9f69dcf88aea89d1492c56"), "location" : [ "US", "CA", "SF" ], "name" : "bar" }
{ "_id" : ObjectId("4d9f6a21f88aea89d1492c5a"), "location" : [ "US", "MA", "BOS" ], "name" : "baz" }
Note that in this model, your values in the array would need to be
unique. So for example, if you had 'springfield' in different states,
then you would need to do some extra work to differentiate.
> db.hierarchical.save({location:['US','MA','Springfield'], name: 'one' })
> db.hierarchical.save({location:['US','IL','Springfield'], name: 'two' })
> db.hierarchical.find({location: 'Springfield'})
{ "_id" : ObjectId("4d9f6b7cf88aea89d1492c5b"), "location" : [ "US", "MA", "Springfield"], "name" : "one" }
{ "_id" : ObjectId("4d9f6b86f88aea89d1492c5c"), "location" : [ "US", "IL", "Springfield"], "name" : "two" }
You can overcome this by using the $all operator and specifying more
levels of the hierarchy. For example:
> db.hierarchical.find({location: { $all : ['US','MA','Springfield']} })
{ "_id" : ObjectId("4d9f6b7cf88aea89d1492c5b"), "location" : [ "US", "MA", "Springfield"], "name" : "one" }
> db.hierarchical.find({location: { $all : ['US','IL','Springfield']} })
{ "_id" : ObjectId("4d9f6b86f88aea89d1492c5c"), "location" : [ "US", "IL", "Springfield"], "name" : "two" }