how to do this query in mongoDB? - mongodb

How do I make this query in mongoDB?
{
_id: "*******"
content: "",
comments: [
{
key1: "1",
key2: "2"
},
{
key1: "sdfs",
key2: "sdfasdf"
}
]
}
For example, I use the data as below. I want to query the items in comments in condition {key1: 1, key2: 2}, and not return the whole record.
What should I do?

You can try to this one
{ "comments.key1" : "1", "comments.key2" : "sdfasdf" }
You only need to use this when more than one field must be matched in the array element.

You can query a subdocument on two fields using $elemMatch:
{ comments: { $elemMatch : { key1: 1, key2: 2 } } }
You cannot return just the selected subdocument. You'll get all of them. So you'll have to filter on the client side. (You can of course, exclude all other fields of the main document).

Related

Mongoose how to use positional operator to pull from double nested array with specific condition, and return new result

Suppose I have the following schema:
{
_id: ObjectId(1),
title: string,
answers: [
{
_id: ObjectId(2),
text: string,
upVotes: [
{
_id: ObjectId(3),
userId: ObjectId(4)
}
]
}
]
}
What I want is pull vote of a specific user from answer upvotes, and return the new update result.
For example, find a question with id 1, and get its specific answer with id 2, then from that answer pull my vote using userId inside upvotes.
I want to do it with a single findOneAndUpdate query
You can even use single $ positional with the $pull operator to update the nested array
db.collection.findOneAndUpdate(
{ "_id": ObjectId(1), "answers._id": ObjectId(2) },
{ "$pull": { "answers.$.upVotes": { "userId": ObjectId(4) }}}
)
I think I understood that you want to do a search in the specific array
db.collection.update(
{
"_id": "507f1f77bcf86cd799439011", // id field
"answers.upVotes._id":"507f1f77bcf86cd799439011" //id array
}
),{
"$set":{"answers.$.upVotes": {userId :"507f1f77bcf86cd799439011"}}},//edit
//use "addToSet" for add

Update array filtering by 2 fields [duplicate]

This question already has an answer here:
Update array with multiple conditions in mongodb
(1 answer)
Closed 4 years ago.
I don't know if it is possible.
I'm trying to do an automatic process to update all elements of a nested array in some documents. The array hasn't a fixed length.
Below is a simplified example of the collection:
{
"_id" : ObjectId("5ba2e413a4dd01725a658c63"),
"MyOwnID" : "123456789",
"MyArray" : [
{
Field1: 'FooName1',
Field2: 'FooSpec1',
FieldToUpdate: '...'
},
{
Field1: 'FooName1',
Field2: 'FooSpec2',
FieldToUpdate: '...'
},
{
... More elements ...
}
]
},
{
"_id" : ObjectId("5ba2e413a4dd01725a658c63"),
"MyOwnID" : "987654321",
"MyArray" : [
{
Field1: 'FooName1',
Field2: 'FooSpec1',
FieldToUpdate: '...'
},
{
Field1: 'FooName2',
Field2: 'FooSpec2',
FieldToUpdate: '...'
},
]
}
I tried and it worked for the first element:
Query for the second element:
db.getCollection('works').findOneAndUpdate(
{ MyOwnID: '123456789', '$and':[ { 'MyArray.Field1': 'FooName1' },{ 'MyArray.Field2': 'FooSpec1' } ] } ,
{ '$set': { 'MyArray.$.FieldToUpdate': 1234} }
)
But when I try to update the second element only the first is updated.
Query for the second element:
db.getCollection('works').findOneAndUpdate(
{ MyOwnID: '123456789', '$and':[ { 'MyArray.Field1': 'FooName1' },{ 'MyArray.Field2': 'FooSpec2' } ] } ,
{ '$set': { 'MyArray.$.FieldToUpdate': 4321} }
)
I tried with arrayFilters option and $elemMatch, both give me an error.
Any options?
You can try below query using $elemMatch
db.getCollection("works").findOneAndUpdate(
{
"MyOwnID": "123456789",
"MyArray": { "$elemMatch": { "Field1": "FooName1", "Field2": "FooSpec2" }}
},
{ "$set": { "MyArray.$.FieldToUpdate": 4321 }}
)
You tried with arrayFilters, but probably in a wrong way, becuse it's working with it. It's not very clear in mongoDB doc, but $[myRef] acts as a placeholder for arrayFilters. Knowing that, you can do this to achieve your goal :
db['01'].findOneAndUpdate(
{MyOwnID: '123456789'},
{$set:{"MyArray.$[object].FieldToUpdate":1234}},
{arrayFilters:[{ $and:[{'object.Field1': 'FooName1' },{ 'object.Field2': 'FooSpec1' }]}]}
)
Note that the unique document in arrayFilters is needed (with $and operator), because both conditions refer to the placeholder. If you put 2 conditions,
({arrayFilters:[{'object.Field1': 'FooName1' },{ 'object.Field2':
'FooSpec1' }]})
MongoDB will complain about two criteria with same base placeholder.
While the answer given by #Anthony Winzlet is right and works perfectly, it will only update the first array element matching conditions defined in $elemMatch, that's why i avoid to use it like that (unless having a unique index on including MyArray.Field1 and MyArray.Field2, you can't be sure that the matching element is unique in your array)

spring-data-mongodb document design options - array vs dynamic field (i.e. map)

I am designing a document structure and use spring-data-mongodb to access it. The document structure is to store device profile. Each device contains modules of different types. The device can contains multiple modules of the same type. Module types are dynamic as new type of modules are created sometimes.
Please note: I try not to write custom queries to avoid boilerplate code. But, some custom queries should be fine.
I come out with two designs:
the first one use dynamic field (i.e. map). Semantics is better but seems harder to query/update using spring-data-mongodb.
{
deviceId: "12345",
instanceTypeMap: {
"type1": {
moduleMap: {
"1": {field1: "value",field2: "value"},
"2": {field1: "value",field2: "value"}
}
},
"type2": {
moduleMap: {
"30": {fielda: "value",fieldb: "value"},
"45": {fielda: "value",fieldb: "value"}
}
}
}
the second one use array and query/update seems more in-line with spring-data-mongodb.
{
deviceId: "12345",
allInstances: [
{
type: 1,
modules: [
{
id: 1,
field1: "value",
field2: "value"
},
{
id: 2,
field1: "value",
field2: "value"
}
]
},
{
type: 2,
modules: [
{
id: 30,
fielda: "value",
fieldb: "value"
},
{
id: 45,
fielda: "value",
fieldb: "value"
}
]
}
]
}
I am inclined to use array. Is it better to use array instead of dynamic field with spring-data-mongodb. I did some search on-line and found people mentioned that query for key (i.e. in map) is not as easy in spring-data-mongodb. Is that a correct statement? Do I miss anything? Thank you in advance.
I ended up with the design as below. I use one device-instance-type per document. Because, in some scenario,
updates are done on many modules of the same instance type. Those updates can be aggregated as just one database update.
The redundant "moduleId" field is also added for query purpose.
{
deviceId: "12345",
instanceTypeId: "type1",
moduleMap: {
"1": {
moduleId: "1",
field1: "value",
field2: "value"
},
"2": {
moduleId: "2",
field1: "value",
field2: "value"
}
}
}
Now, I can use spring-data-mongodb's query:
findByDeviceId("12345");
findByDeviceIdAndInstanceTypeId("12345","type1");
findByDeviceIdAndInstanceTypeIdAndModuleMapModuleId("12345","type1","1");

merge mongodb aggregate result

I have one collection say user. Structure of each document is something like this
_id:String
status:Int32
account:{
firstName:
lastName:
.. some other nested property
}
..some more property
My end goal is to generate a new nested field fullName in accountfield which is a concatenation of two name fields. I can run aggregate query like this
db.user.aggregate(
[
{ $project: { 'account.name': { $concat: [ "$account.firstName", " ", "$account.lastName" ] } } }
])
if I write $out along with db name, but my existing data get replaced. How do I actually merge so that my final structure remains as
_id:String
status:Int32
account:{
firstName:String
lastName:String
fullName:String
.. some other nested property
}
..some more property
In your $project pipeline, you need to include the other fields using the dot notation on the embedded fields as follows:
db.user.aggregate([
{
"$project": {
"status": 1,
"field1": 1, // the other properties
"field2": 1,
"account.firstName": 1,
"account.lastName": 1,
"account.name": {"$concat":["$account.firstName", " ", "$account.lastName"]}
}
},
{ "$out": "tempcollection" }
])

Creating MongoDB index for all items in array

I have some documents in my mongodb database with the following structure, I want to know how to create an index for document.data.0.data[0-9999].val1?
My problem is where I type [0-9999] I don't know how many elements will be inside this data array, but I want that all the elements inside this array have an index on the val1 key.
Any tips?
{
"_id" : ObjectId("55c455c2fc07853b78c4b6b9"),
"data": {
"0": {
"data": [
{
val1: "abc",
val2: "def"
},
{
val1: "abc",
val2: "def"
}
]
}
}
}
You don't include the array index values in the index, so it would just be:
db.mycoll.ensureIndex({'data.0.data.val1': 1})
This is termed a multikey index in MongoDB.