How to query multiple layers of a document in mongodb - mongodb

I have a model in mongodb that looks something like this...
{
username: 'bob',
user_id: '12345',
post: 'Hey everyone, this is my post',
photoID: RANDOM_GENERATED_NUMBER, // each user has their own photoID
comments: [
{
username: 'tom',
user_id: '54321',
post: 'Hey everyone, this is comment 1',
photoID: RANDOM_GENERATED_NUMBER, // each user has their own photoID
responses: [
{
username: 'bob',
user_id: '12345',
post: 'Hey everyone, this is response 2',
photoID: RANDOM_GENERATED_NUMBER, // each user has their own photoID
},
{
username: 'will',
user_id: '35791',
post: 'Hey everyone, this is response 2',
photoID: RANDOM_GENERATED_NUMBER, // each user has their own photoID
}
]
},
{
username: 'bob',
user_id: '12345',
post: 'Hey everyone, this is comment 2',
photoID: RANDOM_GENERATED_NUMBER, // each user has their own photoID
responses: []
}
]
}
On my site, everytime a user changes their profile picture, they get a new 'photoID', referencing the picture, so it can easily be displayed with their username above any posts they make. Because of this, when a user updates their profile picture and gets a new 'photoID', I need to be able to make a query to this 'Post' model that searches for any 'posts', 'comments' or 'responses' that were posted by 'bob'. I then need to update the photoID for that 'post', 'comment' or 'response'.
Is there a query I can use to do this?

You can use a nested elemMatch query.
Possible duplicate of
How to use elemMatch to match nested array

Related

i need to pick the details of post from postCollection how to lookup in mongoose?

[
{
_id: new ObjectId("6236ba6b465ff537abfaa64c"),
firstName: 'user',
lastName: 'uer',
password: '$2a$10$2SX2R1lFEErvcJnO1oGafOK/BRnQ.PG7oLHX0LJ/uuEhrk81NcbnO',
email: 'user1#gmail.com',
phone: 5465465645,
premiumUser: false,
status: true,
authorStatus: false,
indroduction: 'dfghjk',
city: 'asdfadf',
state: 'asdfasdf',
address: 'sdfghjksdaf',
wishlistItems: [
new ObjectId("6231db05a8b12caba4feb39a"),
new ObjectId("6233118f2f06967703e70a4b"),
new ObjectId("6231daa03eedc2006c23b98d"),
new ObjectId("6231d3f1b7b4d0299b8b5e2f"),
new ObjectId("6230dbf77f64b9b25f3939c0"),
new ObjectId("6230d44f6250bcb698a4a5fb")
],
createdAt: 2022-03-20T05:23:55.086Z,
updatedAt: 2022-03-20T05:25:20.516Z,
__v: 0
}
]
the above the is the userCollections.
postCollection below is my postCollection
{
_id: ObjectId('62330fb82f06967703e70a48'),
postTitle: 'GET A PEEK INTO THE FORGOTTEN SIDE OF ASAKUSA,TOKYO',
subTitle: 'Are you a first time visitor to Japan and looking ..',
postIndroduction: 'Are you a first time visitor to Japan and ..',
postContent: 'Pearl Harbor Attack had awakened a sleeping gia.',
place: 'JAPAN',
date: ISODate('2016-05-12T00:00:00.000+00:00'),
authorId: ObjectId('622ad301141ddb7050a78634'),
likeCount: 0,
image1:'https://res.cloudinary.com/ashproduct/image/upload/v1647513503/pzhaddu...',
image2:'https://res.cloudinary.com/ashproduct/image/upload/v1647513506/guooaum...',
image3:'https://res.cloudinary.com/ashproduct/image/upload/v1647513514/rbyh2p4...',
image4:'https://res.cloudinary.com/ashproduct/image/upload/v1647513519/vwwqerz...',
image5:'https://res.cloudinary.com/ashproduct/image/upload/v1647513527/xqyukzj...',
....
};
in my project i need to make wishlist for users. so i make an array list for storing the id of the posts that liked by the user.this wishlist array present in useCollection. its done....But now i need to get that post details to show in another page wishlistItem page.
here i need to get all details of single post from another collection called postCollection on the basis of id present in the collections array userCollection.wishListItems.i am using "mongoose": "^6.2.4"
what should i do to get the result? what is syntax of aggregation for apply this? anyOne please help....
Pretty sure you are looking for "$lookup". Something like:
db.userCollections.aggregate([
{
"$match": {
"_id": ObjectId("6236ba6b465ff537abfaa64c")
}
},
{
"$lookup": {
"from": "postCollections",
"localField": "wishlistItems",
"foreignField": "_id",
"as": "wishPosts"
}
}
])
Try it on mongoplayground.net.

Can I edit multiple documents from an array of them in Mongo?

well...
I have a collection of users, one user looks like
{ userId: "someId", fullName: "AnyName", email: "anyEmail#mail.com"}
and of course Mongo adds one _id
all fine here, but a have an express server and I receive and array of existing users with a POST.
[
{ userId: "123", fullName: "name1 EDITED", email: "anyEmail1#mail.com"},
{ userId: "124", fullName: "name2 EDITED", email: "anyEmail2#mail.com"},
{ userId: "125", fullName: "name3 EDITED", email: "anyEmail3#mail.com"},
{ userId: "126", fullName: "name4 EDITED", email: "anyEmail4#mail.com"}
]
I want edit the existing user with the news values receive in the array but I don't know if I have to iterate and update each document or if I can pass the array of users to update all of them with a single query.
similar to what "insertMany" method does

How to search and update multiple levels of a document in mongodb

I have a model in mongodb that looks something like this...
{
username: 'bob',
user_id: '12345',
post: 'Hey everyone, this is my post',
photoID: RANDOM_GENERATED_NUMBER, // each user has their own photoID
comments: [
{
username: 'tom',
user_id: '54321',
post: 'Hey everyone, this is comment 1',
photoID: RANDOM_GENERATED_NUMBER, // each user has their own photoID
responses: [
{
username: 'bob',
user_id: '12345',
post: 'Hey everyone, this is response 2',
photoID: RANDOM_GENERATED_NUMBER, // each user has their own photoID
},
{
username: 'will',
user_id: '35791',
post: 'Hey everyone, this is response 2',
photoID: RANDOM_GENERATED_NUMBER, // each user has their own photoID
}
]
},
{
username: 'bob',
user_id: '12345',
post: 'Hey everyone, this is comment 2',
photoID: RANDOM_GENERATED_NUMBER, // each user has their own photoID
responses: []
}
]
}
On my site, everytime a user changes their profile picture, they get a new 'photoID', referencing the picture, so it can easily be displayed with their username above any posts they make. Because of this, when a user updates their profile picture and gets a new 'photoID', I need to be able to make a query to this 'Post' model that searches for any 'posts', 'comments' or 'responses' that were posted by 'bob'. I then need to update the photoID for that 'post', 'comment' or 'response'.
Is there a query I can use to do this?
You need two queries to do that task:
Update photoID in subdocuments:
https://mongoplayground.net/p/jTb3qDxIHL1
db.collection.update({},
{
$set: {
"comments.$[c].photoID": "NEW_RANDOM_GENERATED_NUMBER",
"comments.$[].responses.$[r].photoID": "NEW_RANDOM_GENERATED_NUMBER",
},
},
{
multi: true,
arrayFilters: [
{
"c.user_id": "12345",
},
{
"r.user_id": "12345",
},
],
})
Update photoID in document root:
https://mongoplayground.net/p/-Bm4Oykz-1E
db.collection.update({
user_id: "12345"
},
{
$set: {
photoID: "NEW_RANDOM_GENERATED_NUMBER",
}
},
{
multi: true,
})

MongoDB schema and structure

I just started learning mongoDB and mongoose here.
Is it possible to have value as key in mongoDB? For example, I'd like to have a structure like this:
Person collection:
USA: {
'John Doe': { phone: '...', somethingElse: '...' },
'Jane Doe': { phone: '...', somethingElse: '...' },
},
Australia: {
'John Doe': { phone: '...', somethingElse: '...' },
'Jane Doe': { phone: '...', somethingElse: '...' },
},
England: {
'John Doe': { phone: '...', somethingElse: '...' },
'Jane Doe': { phone: '...', somethingElse: '...' },
}
I know it's a terrible example, and I understand alternatively we can store the documents like:
{_id: 1, name: 'John Doe', address: 'USA', phone: '...', ...},
{_id: 2, name: 'John Doe', address: 'Australia', phone: '...', ...},
{_id: 3, name: 'John Doe', address: 'England', phone: '...', ...},
I guess I'm just trying to understand if storing value as key is even possible here. And if it is, how do we define the schema with mongoose?
Theoretically you could use a schema like:
const testSchema = new Schema({
countries: {
type: Map,
of: {
type: Map,
of: Object,
},
},
});
taking advantage of Map type in mongoose, then you can assign your dynamic object to contries property.
Personally I believe that second approach you mentioned is a way better idea (unless you really have a good reason for using the first one).
First reason is that having dynamic key names makes querying difficult. Instead of simple .find({name: 'John Doe'}) you need to run complicated aggregation queries like here. Basically any traversing like counting people, filtering by phone etc will be painful with dynamic keys.
Second reason is that MongoDB document has 16MB limitation so gathering too many people means you can approach that limit.

Mongoose/mongo many to many with computed field

This is my schema. Each user has many posts and each post has list of users who favorited it.
var User = mongoose.model('User', {
name: String,
posts: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Post' }]
});
var Post = mongoose.model('Post', {
name: String,
favorited: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }]
});
I need to select all user posts with a boolean flag is it favorited or not.
I've started with:
User.findById('56e14680476f47200f1f598e')
.populate('posts')
.then(u => {
console.log(u);
})
.catch(console.error.bind(console));
Output:
[ { favorited: [Object],
__v: 0,
name: 'post 1',
_id: 56e14680476f47200f1f5991 },
{ favorited: [],
__v: 0,
name: 'post 2',
_id: 56e14680476f47200f1f5992 },
{ favorited: [],
__v: 0,
name: 'post 3',
_id: 56e14680476f47200f1f5993 } ],
__v: 0,
name: 'user 1',
_id: 56e14680476f47200f1f598e }
Aggregation, map-reduce, or maybe re-design schema? Maybe there are good examples of complex structures? Where to dig?
Please try this one
User.findById('56e14680476f47200f1f598e')
.populate('posts')
.exec(function(err, user) {
if (err)
console.log(err);
else{
// populate `posts` again
Post.populate(user.posts, {path:'favorited', model: 'User'}, function(err, ret) {
if (err)
console.log(err);
else
console.log(require('util').inspect(ret, { showHidden: true, depth: null }));
})
}
});
Second thought, if there are litter fields in User collection, you could just nest user information into Post collection, rather than reference it.
var Post = mongoose.model('Post', {
name: String,
favorited: [{ name: String,
// other fields...
}]
});
One concern is that, if there are many favorited users could make the Post collection too large. Make sure no more the collection limit, 16 megabytes.
Whatever, the data schema should meet your data, and facilitate to query it.