I have multiple users in my collection and each user has an object of sessions shown below
{
user: 'adam',
sessions: {
key: some-value,
key: some-value
}
}
{
user: 'chris',
sessions: {
key: some-value,
key: some-value
}
}
I fetch the document on the basis of the user name. let us say i want the sessions of adam.
So I run db.collection.find({ user: 'Adam' }) which gives me full document of adam. Now I want the sessions of 'Adam' but the sessions object should be converted into an array of objects like this :
{
user: 'adam'
sessions : [ { key: value },{ key: value } ]
}
I want to convert the sessions of user into an object that means i want to do $objectToArray but on a specific username not the full collection.
Just the user I want.
Explanation:
I am running node as backend and i have a route called 'getuserdata' which gets data for a specific user based on the username. So when i will hit that route with username adam and it will get the data from the DB. The sessions of adam should come in an array of objects like shown above instead of an object which is in the db.
What i am doing
I am running a for-in loop on the back-end to convert them into array of objects but it is slow.
You can do it using $map in project part,
$map input sessions as array to convert using $objectToArray,
inside map convert array of object key and value to $arrayToObject
db.collection.find(
{ user: "adam" },
{
user: 1,
sessions: {
$map: {
input: { $objectToArray: "$sessions" },
in: { $arrayToObject: [["$$this"]] }
}
}
})
Playground
//run from mongodb client
//sample user data preparation
> db.users15.find();
{ "_id" : ObjectId("5f4fbfbc3372ab5da3a605ac"), "user" : "adam", "sessions" : { "key1" : 1123, "key2" : 1124 } }
{ "_id" : ObjectId("5f4fbfbc3372ab5da3a605ad"), "user" : "chris", "sessions" : { "key1" : 2122, "key2" : 2134 } }
// Mongo query, variable defined an user for dynamic passing in match condition
> var v_user = "adam"
> db.users15.aggregate([
... {$match:{user:v_user}},
... {$project:{user:1,
... sessionArray:{$objectToArray:"$sessions"}
... }
... }
... ]);
//output showing conversion from session object to array for key value pair
{ "_id" : ObjectId("5f4fbfbc3372ab5da3a605ac"), "user" : "adam", "sessionArray" : [ { "k" : "key1", "v" : 1123 }, { "k" : "key2", "v" : 1124 } ] }
>
//Further,the mongo query gives correct output for nested objects as well.
//Example below.
> db.users15.find().pretty();
{
"_id" : ObjectId("5f4fbfbc3372ab5da3a605ac"),
"user" : "adam",
"sessions" : {
"key1" : 1123,
"key2" : 1124
}
}
{
"_id" : ObjectId("5f4fbfbc3372ab5da3a605ad"),
"user" : "chris",
"sessions" : {
"key1" : 2122,
"key2" : 2134
}
}
{
"_id" : ObjectId("5f5069ed3372ab5da3a605ae"),
"user" : "sriny",
"sessions" : {
"key1" : 2122,
"key2" : 2134,
"key3" : {
"server1" : 2344,
"server2" : 9999
}
}
}
>
> var v_user = "sriny"
> db.users15.aggregate([
... {$match:{user:v_user}},
... {$project:{user:1,
... sessionArray:{$objectToArray:"$sessions"}
... }
... }
... ]).pretty();
{
"_id" : ObjectId("5f5069ed3372ab5da3a605ae"),
"user" : "sriny",
"sessionArray" : [
{
"k" : "key1",
"v" : 2122
},
{
"k" : "key2",
"v" : 2134
},
{
"k" : "key3",
"v" : {
"server1" : 2344,
"server2" : 9999
}
}
]
}
>
Take for example this object
const obj = {
key1: "value1",
key2: "value2"
}
We can map this to pattern [ { key1: value1 }, { key2: value2 } ] using a map on the object keys
const arrayFromObj = Object.keys(obj).map(value => {
return { value: obj[value] }
})
Related
I'd like to update the value of the key shouldSendAlert in the following document:
{
"_id" : ObjectId("5c61c4db46d18e1092c5b024"),
"service" : "SRVPVD",
"menu" : [
{
"sub" : [
{
"options" : [
{
"item" : [
{
"name" : "",
"actions" : [
{
"name" : "communicateClient",
"value" : true
},
{
"name" : "shouldSendAlert",
"value" : false
}
]
}
],
"name" : "Technology Support"
},
{
"item" : [
{
"name" : "",
"actions" : [
{
"name" : "communicateClient",
"value" : true
}
]
}
],
"name" : "Company Support"
}
],
"name" : "Support"
},
{
"name" : " FAQ"
}
],
"name" : "Help"
}
]
}
I've managed to do this, querying the document using a multiple $elemMatch query, and using forEach to run through the nested arrays in order to alter the value of shouldSendAlert:
{
let menuItems = db.getCollection('menumodels').find({menu: {$elemMatch: {name: 'Help',sub: {$elemMatch: {name: 'Support',motivos: {$elemMatch: {name: 'Technology Support'}}}}}}});
menuItems.forEach((r) => {
r.menu.forEach(menuItem => {
if (menuItem.name == 'Help') {
menuItem.sub.forEach(sub => {
if (sub.name == 'Support') {
sub.motivos.forEach(motivo => {
if (motivo.name == "Technology Support") {
motivo.item[0].actions.forEach(action => {
if (action.name == 'shouldSendAlert') {
action.value = true;
db.getCollection('menumodels').update({_id: r._id}, {$set: {menu: r.menu}})
}
})
}
})
}
})
}
})
});
}
Is it - regarding performance - necessary, to code this MongoDB query
or update logic into a smarter form? Does the multiple use of $elemMatch affect performance?
I want to sum counts values for each beacon. I'm using aggregate query but it returns with counts 0. Please let me know if there is mistake in query.
Sample Data
[ {
"_id" : ObjectId("5a8166392aa41ec66efc66bf"),
"userID" : "5a7c3410bdff0f0014181874",
"date" : ISODate("2018-02-08T11:04:54.000Z"),
"beacons" : [
{
"counts" : "2",
"UUID" : "red"
},
{
"counts" : "1",
"UUID" : "blue"
}
]
},
{
"_id" : ObjectId("5a8166392aa41ec66efc66c0"),
"userID" : "5a7c3410bdff0f0014181874",
"date" : ISODate("2018-02-08T11:04:54.000Z"),
"beacons" : [
{
"counts" : "2",
"UUID" : "red"
},
{
"counts" : "1",
"UUID" : "blue"
}
]
}
]
Query
/* Query */
db.getCollection('CountsDetail')
.aggregate([
{
"$unwind":"$beacons"
},
{
"$group": {
"_id":"$beacons.UUID", "counts":{ "$sum":"$counts"}
}
}]);
Response
/* Response */
{
"_id" : "red",
"counts" : 0
}
{
"_id" : "blue",
"counts" : 0
}
Response is returning 0 in sum, which is weird. Please correct what I am doing wrong. Thanks
Sorry miss read your OP. Your counts field is nested so use a dot notation:
"counts":{ "$sum":"$beacons.counts"}
I have a collection of the structure as follows:
collection name : "positions"
Structure
{
"_id" : "vtQ3tFXg8THF3TNBc",
"candidatesActions" : {
"sourced" : [ ],
},
"appFormObject" : {
"name" : "✶ mandatory",
"questions" : [
{
"qusId" : "qs-585494",
"type" : "simple",
"qus" : "Which was your previous company"
},
{
"qusId" : "qs-867766",
"type" : "yesNo",
"qus" : "Are you willing to relocate?",
"disqualify" : "true"
}
]
}
}
I want to update "qus" field of the above collection whose _id is "vtQ3tFXg8THF3TNBc" and "qusId" is "qs-585494".
Try following....
db.positions.update(
{_id: "vtQ3tFXg8THF3TNBc", "appFormObject.questions.qusId":"qs-585494"},
{$set:{"appFormObject.questions.$.qus": "this is updated value"}}
)
Use following query
db.positions.findAndModify({
query: { _id: "vtQ3tFXg8THF3TNBc", "appFormObject.questions.qusId":"qs-585494"} ,
update: { $set: { 'appFormObject.questions.$.qus': 'Brilliant Green' } },
});
Thanks
I need to achieve such collection structure:
{
"_id" : "36JaTS8N9uJDHabaq",
"pages" : {
1 : {
"field1" : "value1",
"field2" : "value2"
},
...
}
}
Everything is fine, when I'm doing the following:
Collection.insert({
"pages": {
1: {
"field1" : "value1",
"field2" : "value2"
}
}
})
But when I'm trying to use the variable containing the number instead of number itself, like:
var number = 1;
Collection.insert({
"pages": {
number: {
"field1" : "value1",
"field2" : "value2"
}
}
})
I receive not the result I want (there is a variable name where number should be):
{
"_id" : "SjMotZHrtXviuoyqv",
"pages" : {
"number" : {
"field1" : "value1",
"field2" : "value2"
}
}
}
What is the right way to do what I'm trying to achieve?
Thanks in advance!
You can try something like this :
var doc={
pages:{}
};
var number="1";
doc.pages[number]={
"field1":"value1",
"field2":"value2"
};
Collection.insert(doc);
You can't use variables as keys in object literals in javascript. See this answer.
var number = 1;
var pages = {};
pages[number] = {f1: 'v1', f2: 'v2'};
Collection.insert({pages: pages});
My JSON currently looks like this:
{
"_id" : 393,
"item" : 34,
"comments" : [
{
"name" : "kevin",
"messages" : [
"item",
"item"
]
},
{
"name" : "ryan",
"messages" : [
"item",
"item"
]
}
]
}
How could I push new items onto the messages array for the first or second item in the comments array?
db.newcon.update({_id: 393}, { $push: { comments['kevin']: {messages: 39 } } })
Using $elemMatch and $ operator you can update your documents check below query :
db.collectionName.update({"_id":393,"comments":{"$elemMatch":{"name":"kevin"}}},
{"$push":{"comments.$.messages":39}})
Something like this will work:
var newMessage = '39';
comments.forEach(function(item) {
if (item.name === 'kevin') {
item.comments.push(newMessage);
}
});