Update Subdocument in Mongodb that stores id(s) - mongodb

I am developing an application and we have decided to implement database with Mongodb, so I'm truly new to it. In database there is a collection for each company and we need to stores the ID(s) of each category of products of the company in a subdocument of company collection, Let's say we need to insert the following Object into collection:
{
name : "comapnyX"
address : {
"street" : "main street",
"ZipCode" : "12345"
},
categories : [
{ "name" : "category1" },
{ name" : "category2" }
]
}
An then if later on we decide to update the categories, we need add one more category to this subdocument, how do I have to create that update?
please also let me know if this is not a good practice from Datamodeling point of view in Mongodb

You can use the update method with the $push operator to add a new category:
db.collection.update( <query>,
{ $push: { categories: {name: "category3" } }
)
MongoDB Docs on $push: http://docs.mongodb.org/manual/reference/operator/update/push/

Related

How to find objectId as an foreign key in mongo

How can I find the value of ObjectId in whole database for any field in mongo ,
it might be use in some collections for various fields as a reference?
"fourk_runs": [{
"Objectid": "6299b9f00f09ff045cc15d"
}],
"fourk_pass_fail": [{
"Objectid": "6299b9f00f09ff045cc152"
}],
"dr_runs": [{
"Objectid": "6299b9f00f09ff045cc154"
}],
I try this command , but it does not work
db.test.find( { $text: { $search: "4c8a331bda76c559ef04" } } )
In MongoDB, the references are mostly used for the normalization process. The references from the children's table (usually an ObjectID) are then embedded in the parent table. When reading the information, the user has to perform several queries in order to retrieve data from multiple collections.
For example, we will take the next two collections, parts and products. A product will contain many parts that will be referenced in the product collection.
parts Collection:
db.parts.findOne()
{
_id : ObjectID('1111'),
partno : '7624-faef-2615',
name : 'bearing',
price: 20,000
}
products Collection:
db.products.findOne()
{
name : 'wheel',
manufacturer : 'BMW',
catalog_number: 1134,
parts : [ // array of references to Part documents
ObjectID('1111'), // reference to the bearing above
ObjectID('3f3g'), // reference to a different Part
ObjectID('234r'),
// etc
]
}
To receive the parts for a particular product, we will first have to fetch the product document identified by the catalog number:
db.products.findOne({catalog_number: 1134});
Then, fetch all the parts that are linked to this product:
db.parts.find({_id: { $in : product.parts } } ).toArray();

how to update model from a list of documents to an array in mongodb

We have a MongoDB instance with a collection of users that is something like this:
{
"Username": "Amin-AMD",
"FriendsList": [
{
"UserId": "5e076f4b19e8cd000162c962",
"NickName": "Amin-Mobile",
"ClanName": null,
"ClanId": null,
"Level": NumberInt(1),
"ActiveCosmeticItems": [
"hair0",
"skin0",
"eye0",
"mouth0",
"daub0",
"acc"
],
"IsOnline": false
},
{
"UserId": "5e08a4a119e8cd000167929e",
"NickName": "saeed",
"ClanName": null,
"ClanId": null,
"Level": NumberInt(7),
"ActiveCosmeticItems": [
"hair5",
"skin2",
"eye2",
"mouth10",
"daub0",
"acc0"
],
"IsOnline": false
}
]
}
As shown above, I have embedded a list of Friends in our User's collection. but for a reason, we need to change this model to reference Friends. So I need to write a query to replace the whole FriendModel with just a UserId.
I have reached to this query but it throws an exception.
db.Users.updateMany({ "FriendsList" : { $ne : [] }}, { $set : { "FriendsList.$" : "FriendsList.$.UserId" }})
In fact, for each friend, I just need the UserId so the new FriendsList will be an array and it should be something like this:
{
"Username": "Amin-AMD",
"FriendsList": [
"5e076f4b19e8cd000162c962",
"5e08a4a119e8cd000167929e"
]
}
MongoDB version: 4.2.1
You have to do it in two steps :
Update existing data in DB :
As you can use aggregation pipeline in updates starting MongoDB version 4.2.
Query to update data :
db.collection.updateMany({ "FriendsList" : { $ne : [] }},[{$set :{FriendsList: '$FriendsList.UserId'}}])
But if your FriendsList.UserId are strings better convert them to ObjectId() as like below :
db.colleciton.updateMany({ "FriendsList" : { $ne : [] }},[{$set :{FriendsList: { $map: { input: '$FriendsList.UserId', in: {$toObjectId: '$$this'}} }}}])
Update existing mongoose model to restrict future writes on DB :
Mongoose Model :
So FriendsList will be an array of ObjectId()'s which will be referred to another new schema via ref field.
FriendsList:[{
type: mongoose.Schema.Types.ObjectId,
ref: "FriendList" /** 'FriendList' will be a mongoose schema refers to a collection */
}]
Ref : mongoose-populate
Try using User model
FriendsList:{
type: mongoose.Schema.Types.ObjectId,
ref: "FriendList"
}

Text query through referenced objects with MongoDB

I have the following structure.
books collection:
{
_id: "book_1",
title: "How to build a house",
authorId: "author_1"
}
{
_id: "book_2",
title: "How to plant a tree",
authorId: "author_2"
}
authors collection:
{
_id: "author_1",
name: "Adam Adamson"
}
{
_id: "author_2",
name: "Brent Brentson"
}
I want to make a case insensitive free text search with the string "b" through the books collection and find all books that either has the "b" in the title or has an author with "b" in the name.
I can embed the author in the book object just to be able to make the query. But if the author name changes in the authors collection, the embedded authors object will have the wrong name.
{
_id: "book_2",
title: "How to plant a tree",
authorId: "author_2",
author:
{
name: "Brent Brentson"
}
}
What would be a good way to solve this problem?
You could use the following queries where the first gets the array of author ids that match the given regex expression query on the authors collection (using the map() method of the find() cursor) and the second query applies that array in the books collection query using the $in operator as well as using the regex pattern to find books that have "b" in the title:
var authorIds = db.authors.find({"name": /b/i}).map(function (doc) {return doc._id});
db.books.find({$or: [{"title": /b/i}, {"authorId": {"$in": authorIds} }]})
Result:
/* 0 */
{
"_id" : "book_1",
"title" : "How to build a house",
"authorId" : "author_1"
}
/* 1 */
{
"_id" : "book_2",
"title" : "How to plant a tree",
"authorId" : "author_2"
}
-- UPDATE --
Thanks to #yogesh for suggesting another approach which uses the distinct() method to get the author ids list:
var authorIds = db.authors.distinct("_id", {"name": /b/i})

Mongodb: Trying to find all documents with specific subdocument field, why is my query not working?

Here is an example of a document from the collection I am querying
meteor:PRIMARY> db.research.findOne({_id: 'Z2zzA7dx6unkzKiSn'})
{
"_id" : "Z2zzA7dx6unkzKiSn",
"_userId" : "NtE3ANq2b2PbWSEqu",
"collaborators" : [
{
"userId" : "aTPzFad8DdFXxRrX4"
}
],
"name" : "new one",
"pending" : {
"collaborators" : [ ]
}
}
I want to find all documents within this collection with either _userId: 'aTPzFad8DdFXxRrX4' or from the collaborators array, userId: 'aTPzFad8DdFXxRrX4'
So I want to look though the collection and check if the _userId field is 'aTPzFad8DdFXxRrX4'. If not then check the collaborators array on the document and check if there is an object with userId: 'aTPzFad8DdFXxRrX4'.
Here is the query I am trying to use:
db.research.find({$or: [{_userId: 'aTPzFad8DdFXxRrX4'}, {collaborators: {$in: [{userId: 'aTPzFad8DdFXxRrX4'}]}}] })
It does not find the document and gives me a syntax error. What is my issue here? Thanks
The $in operator is basically a simplified version of $or but you really only have one argument here so you should not even need it. Use dot notation instead:
db.research.find({
'$or': [
{ '_userId': 'aTPzFad8DdFXxRrX4'},
{ 'collaborators.userId': 'aTPzFad8DdFXxRrX4'}
]
})
If you need more than one value then use $in:
db.research.find({
'$or': [
{ '_userId': 'aTPzFad8DdFXxRrX4'},
{ 'collaborators.userId': {
'$in': ['aTPzFad8DdFXxRrX4','aTPzFad8DdFXxRrX5']
}}
]
})

Meteor upsert - using addToSet and each

I have a Groups collection that contains an eventId and an array of guest ids. I am trying to use upsert to check if an eventId and current guest id already exist, and if so update the collection with the new guest id pushed to the guests array, otherwise insert the new collection with both the current guest and new guest. Here's my upsert code:
var groupId = Groups.upsert({
$and:[
{eventId:groupAttributes.eventId}, // find all the Groups associated w/ this event
{ "guests": {$in: [guest]}}, // and include this guest
]
},{$set: group,
$addToSet: {guests: {$each: [ guest, groupAttributes.guest ]} }
});
What actually happens is a new Group is created everytime, and it's because the $each modifier isn't allowing $addToSet to add multiple values to an array as described here http://docs.mongodb.org/manual/reference/operator/update/addToSet/#up._S_addToSet
Instead what happens is the guests array is added with an "$each" array of size 2.
[{"$each":["yQZfEXfs7J9E4Nbqf","s2rk5KAxq4dYtDFNG"]}]
Two questions. 1) Is there a better way to do what I am trying to do, and if not 2) What am I doing incorrectly? Thanks.
Edit: Trying the following code in meteor mongo
db.groups.update({
$and:[
{eventId:"wGMhaP7t4nsiTNHt5"},
{ "guests": {$in: ["yQZfEXfs7J9E4Nbqf"]}},
]
},{$set: { userId: 'gBuR448nsJMcpwjsT',
author: 'Martin W',
weddingId: 'rz9xjtDm3bFAeiCxM',
eventId: 'wGMhaP7t4nsiTNHt5' },
$addToSet: {guests: {$each: [ "yQZfEXfs7J9E4Nbqf","s2rk5KAxq4dYtDFNG" ]} }
}, {upsert: true})
The result is the following
{ "_id" : ObjectId("528fa31a098141f336688d96"), "author" : "Martin W", "eventId"
: "wGMhaP7t4nsiTNHt5", "guests" : [ "yQZfEXfs7J9E4Nbqf", "s2rk5KAxq4dYtDFNG"
], "userId" : "gBuR448nsJMcpwjsT", "weddingId" : "rz9xjtDm3bFAeiCxM" }
Now I try the same code in Meteor
var groupId = Groups.update({
$and:[
{eventId:"wGMhaP7t4nsiTNHt5"},
{ "guests": {$in: ["yQZfEXfs7J9E4Nbqf"]}},
]
},{$set: { userId: 'gBuR448nsJMcpwjsT',
author: 'Martin W',
weddingId: 'rz9xjtDm3bFAeiCxM',
eventId: 'wGMhaP7t4nsiTNHt5' },
$addToSet: {guests: {$each: [ "yQZfEXfs7J9E4Nbqf","s2rk5KAxq4dYtDFNG" ]} }
}, {upsert: true})
And the result is different (and undesirable)
{ "_id" : "4XgaF6pBGEohQR6pa", "userId" : "gBuR448nsJMcpwjsT", "author" : "Marti
n W", "weddingId" : "rz9xjtDm3bFAeiCxM", "eventId" : "wGMhaP7t4nsiTNHt5", "guest
s" : [ { "$each" : [ "yQZfEXfs7J9E4Nbqf", "s2rk5KAxq4dYtDFNG" ] } ] }
I am a mongo newb so am not sure what to make of it, but I notice how the _id is an ObjectId in the first result and not in the second. And the guests array is the way I would expect using meteor mongo, but using $each as a value in the second result set. Any ideas?