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

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
}

Related

MongoDB: index enums and nullable fields for search?

I have a "log" type of collection, where depending on the source, there might be some id-fields. I want to search those fields with queries, but not sort by them. should I index them to improve search performance? To visualize the problem:
[{
_id: ObjectID("...") // unique
userId: ObjectID("...") // not unique
createdAt: ...
type: 'USER_CREATED'
},
{
_id: ObjectID("...") // unique
basketId: ObjectID("...") // not unique
createdAt: ...
type: 'BASKET_CREATED'
},
...]
I want to filter by (nullable) userId or basketId as well as the type-enum. I am not sure if those fields need an index. createdAT certainly does since it it is sortable. But sparse fields containing enums or null (and simply non-unique) values: how should those be treated as a rule of thumb?

Mongoose/MongoDB - Can I find a document by mapping through an array of ids that it contains?

I have a document model that contains an array of user objects. What I want to do is return the document if that array contains an object with a specific user _id. Is this possible?
Something like
{
_id: 1
name: 'Document with Array of User Ids'
arrayOfUsers: [
{
name: 'John Doe',
_id: 2
},
{
name: 'Michael Scott',
_id: 3
}
]
}
And then returning all documents that have an _id of 3 in arrayOfUsers
Thanks!
You can use dot notation like so:
https://mongoplayground.net/p/iu0f68D1vbL
Model.find({
"arrayOfUsers._id": 2
})
https://docs.mongodb.com/manual/tutorial/query-embedded-documents/#query-on-nested-field

How to refer currently updating records in mongoDB query?

Below is my collection
[{documentId: 123, id: uniqueValue }]
Expected result
[{documentId: 123, id: id1,uniqueKey: uniqueValue }]
How do I refer "id" column for currently updating records, also id column can be anything for which my outer query is giving me the column name
db.supplier.updateMany( { documentId : 123}, { $set: { "uniqueKey": id} } );
so in above query "id" is coming like outerObject.mapping.idColumn which I want to substitute in above query.
The whole point of doing this, is to create index on column, and current collection does not have fixed column name on which I want to fire a query
Example
There are two collections collectionOne and collectionTwo
for each document in collectionOne there are multiple document in collectionTwo. The docId is used for lookup.
collectionOne
[{
docId :123,
col1 : lookupColumn
metaData: "some metaData",
extra : "extra columns"
}, ... ]
collectionTwo
[{
docId :123,
lookupColumn:"1",
a:"A",
b:"B" ....
},
{ docId :123,
lookupColumn:"2",
a:"A",
b:"B" ....
}
{ docId :123,
lookupColumn:"3",
a:"A",
b:"B" ....},.....]
lookupColumn in collectionTwo may have different name and mapping of that name is given in collectionOne by col1 field (which is always same), in this example col1 value is lookupColumn so I want to create a column newKey and copy value of lookupColumn into it.
So I came up with below Query
db.collectionOne.find({}).forEach(function(obj) {
if(obj.columns) {
existingColumn =obj.columns.col1;
db.collectionTwo.updateMany( { docId: obj.docId}, { $set: { "newKey": existingColumn} } );
}
}
problem is I am not able to pick an existing column name using variable existingColumn, I have tried using $ as well, which inserts $"existingColumn" as newKey value.
I have updated query with one more loop over collectionTwo but I feel that in optimized and unnecessary.
To go from
{documentId: 123, id: uniqueValue }
to
{documentId: 123, id: id1, uniqueKey: uniqueValue }
Use the pipeline style of update, which lets you use aggregation syntax:
db.collection.update({documentId: 123}, [{$set:{uniqueKey:"$id", id:"id1"}}])
EDIT
The latest edit to the question makes this a lot more clear.
You were almost there.
In MongoDB 4.2, the second argument to updateMany accepts either an update document like you were using:
db.collectionTwo.updateMany( { docId: obj.docId}, { $set: { "newKey": existingColumn} } );
Or it can accept an aggregation-like pipeline, but not all stages are available. For this use, if you make that second argument an array so that it is recognized as a pipeline, you can use the "$variable" structure. Since you already have the field name in a javascript variable, prepend "$" to the fieldname:
db.collectionTwo.updateMany( { docId: obj.docId}, [{ $set: { "newKey": "$" + existingColumn} }] );

How to query a document using mongoose and send the document to the client with only one relevant element from an array field to the client?

I have the following schema:
var lessonSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: String,
students: [{
_id: mongoose.Schema.Types.ObjectId,
attendance: {
type: Boolean,
default: false,
},
}],
});
The students array is an array of students who attended the particular lesson. I want to find a lesson using whether a particular user is present in the students array and then sent only that element of the students array which corresponds to the user making the request, along with all other fields as it is. For example, the query should return:
{
_id: 'objectid',
name: 'lesson-name'
students: [details of just the one student corresponding to req.user._id]
}
I tried using:
Lesson.find({'students._id': String(req.user._id)}, {"students.$": 1})
The query returns the document with just the id and the relevant element from the students array:
{
_id: 'objectid'
students: [details of the one student corresponding to req.user._id]
}
I tried using:
Lesson.find({'students._id': mongoose.Types.ObjectId(req.user._id)})
This returns the document with the details of all the students:
{
_id: 'objectid',
name: 'lesson-name'
students: [array containing details of all the students who attended the lesson]
}
How can I modify the query to return it the way I want?
You can return the name field by adding it to the projection object like this:
Lesson.find({ "students._id": String(req.user._id) }, { "name": 1, "students.$": 1 })
When you add a projection object (2nd parameter to find), the _id field is returned by default, plus whichever fields you set to 1.
Therefore, you were returning just the _id and the desired student but not the name field.
If you want to return all other fields and just limit the array to the matched item then you can make use of $slice in your projection:
Lesson.find({ "students._id": String(req.user._id) }, { "students.$": { $slice: 1 } })

mongo: update subdocument's array

I have the following schema:
{
_id: objectID('593f8c591aa95154cfebe612'),
name: 'test'
businesses: [
{
_id: objectID('5967bd5f1aa9515fd9cdc87f'),
likes: [objectID('595796811aa9514c862033a1'), objectID('593f8c591ba95154cfebe790')]
}
{
_id: objectID('59579ff91aa9514f600cbba6'),
likes: [objectID('693f8c554aa95154cfebe146'), objectID('193f8c591ba95154cfeber790')]
}
]
}
I need to update "businesses.likes" where businesses._id equal to a center value and where businesses.likes contains certain objectID.
If the objectID exists in the array, I want to remove it.
This is what I have tried and didn't work correctly, because $in is searching in all the subdocuments, instead of the only subdocument where businesses._id = with my value:
db.col.update(
{ businesses._id: objectID('5967bd5f1aa9515fd9cdc87f'), 'businesses.likes': {$in: [objectID('193f8c591ba95154cfeber790')]}},
{$pull: {'businesses.$.likes': objectID('193f8c591ba95154cfeber790')}}
)
Any ideas how how I can write the query? Keep in mind that businesses.likes from different businesses can have the same objectID's.