How to print nested array using mongo query - mongodb

I'm trying to print the values of an nested array.But getting execute script error.How do I print object BSON and avoid error in for nested array.
Note : I want to do with print and not find().
Customer schema
{
"name" : "Sam",
"phone" : [
{
"home" : "123456",
"work" : "045842"
}]}
query
db.getCollection('customer').find({}).forEach( function(cust)
{
print("Customer Name : " + cust.name); // prints Sam
print("Home Contact : " + cust.phone) // prints [object BSON]
print("Home Contact : " + cust.phone.home) // throws error
});

You could use aggregation if there are multiple items in the array
db.collectionName.aggregate([
{ $unwind: { path: "$phone", preserveNullAndEmptyArrays: true}},
]).forEach(function(doc){
print(doc.name)
if(doc.phone !== undefined) print(doc.phone.home)
if(doc.phone !== undefined) print(doc.phone.work)
})

You just need to convert the object to string and access the array;
print("Home Contact : " + JSON.stringify(cust.phone[0]))
// prints ` Home Contact: { "home" : "123456", "work" : "045842" }
print("Home Contact : " + cust.phone[0].home) // "123456"
An example:
aireclaimRs:PRIMARY> use test
switched to db test
aireclaimRs:PRIMARY> db.createCollection('customer')
{ "ok" : 1 }
aireclaimRs:PRIMARY> db.customer.insert( {
... "name" : "Sam",
... "phone" : [
... {
... "home" : "123456",
... "work" : "045842"
... }]})
WriteResult({ "nInserted" : 1 })
aireclaimRs:PRIMARY> db.getCollection('customer').find().forEach(function(cust){
... print("Customer Name : " + cust.name);
... print("Homes Contact : " + JSON.stringify(cust.phone[0]));
... print("Home Contact : " + cust.phone[0].home)
... })
Customer Name : Sam
Homes Contact : {"home":"123456","work":"045842"}
Home Contact : 123456

Related

How to find an index array inside the MongoDB document

I have one collection with this document format:
{
"_id" : ObjectId("5c51fe3a6abdf0e5cd78f658"),
"0" : {
"id" : 1,
"name" : "carlos"
},
"1" : {
"id" : 2,
"name" : "foo"
},
"2" : {
"id" : 3,
"name" : "Jhon Doe"
},
"3" : {
"id" : 4,
"name" : "Max"
}
}
the only way to access the properties was doing a foreach loop and another for in inside.
db.getCollection('tutorial').find({}).forEach( (users) => {
for(user in users){
print("ID-> " + users[user].id, " Name->" + users[user].name);
}
});
But I can only print the results, there is another way to return a value using find ?
Thanks in advance.
You have to split up your operations. Get the collection first and then run a function to return the value you wish:
let collection = db.getCollection('tutorial').find({});
let name = () => {collection.forEach( (users) => {
for(user in users){
if(users[user].name == "foo"){
return ("ID-> " + users[user].id, " Name->" + users[user].name);
}
}
})};
or simply create a variable and set it when you run the loops
let name;
db.getCollection('tutorial').find({}).forEach( (users) => {
for(user in users){
name = ("ID-> " + users[user].id, " Name->" + users[user].name);
}
});
or something similar
Though all of these scenarios seem like a strange way to handle a mongo collection. I would definitely recommend restructuring your collection if you can't access the data using regular find method.

Mongodb connection to table in function

I don't know how should refer I to a table, maybe someone knows and can help:
Collection:
{
"_id" : ObjectId("5a5e40636494620e7471c51b"),
"uczelnia" : "Politechnika Wroclawska",
"ulica" : "Jodlowa 15",
"doktorzy" : [
{
"imie" : "Mateusz",
"nazwisko" : "Laskowski"
},
{
"imie" : "Piotr",
"nazwisko" : "Potrzebny"
}
],
"miejscowosc" : "Wroclaw"
}ObjectId("5a5e40636494620e7471c51b"
Function:
function dane_o_uczelni(id) {
uczelnia1= db.uczelnia.findOne({"_id" : id})
if(uczelnia1!==null)
{
print("Uczelnia: "+ uczelnia1.uczelnia)
print("Miejscowosc: " + uczelnia1.miejscowosc)
print("Doktorzy: " + uczelnia1.doktorzy.nazwisko)
}
else return null
}
dane_o_uczelni(ObjectId("5a5e40636494620e7471c51b"));
I want to see on output all of my Doctor(doktorzy) in ObjectId("5a5e40636494620e7471c51b" with surname (nazwisko). With this code I see only uczelnia and ulica, in nazwisko I see information undefined..

Mongodb - E QUERY SyntaxError: Unexpected identifier

Here is an example of my MongoDb structure :
{
"id" : 1,
"children" : [
{
"id" : 2,
"status" : " fsdfsdf "
},
{
"id" : 3,
"status" : " ffdfg "
},
{
"id" : 4,
"status" : " fsdfsdfsdfdsf "
}
]
}
I wanted to trim records in mongodb, so i did :
db.getCollection('myCollectionName').find().forEach(function (doc){
for (subDoc of doc.children) {
if(typeof subDoc.status === 'string') {
subDoc.theText = subDoc.theText.trim();
}
}
db.getCollection('myCollectionName').save(doc);
})
But i got this error :
E QUERY SyntaxError: Unexpected identifier
You use wrong identifier — the array item doesn't have theText identifier.
var docs = db.getCollection('myCollectionName').find()
docs.forEach(function (doc) {
for (subDoc of doc.children) {
if(typeof subDoc.status === 'string') {
subDoc.status = subDoc.status.trim();
}
}
db.getCollection('myCollectionName').save(doc);
})
Step by Step instructions
Open local mongo shell with db stackoverflow
⋊> ~ mongo stackoverflow
MongoDB shell version v3.4.1
connecting to: mongodb://127.0.0.1:27017/stackoverflow
MongoDB server version: 3.4.0
Insert one (your) document
> db.getCollection('myCollectionName').insertOne({
... "id" : 1,
... "children" : [
... {
... "id" : 2,
... "status" : " fsdfsdf "
... },
... {
... "id" : 3,
... "status" : " ffdfg "
... },
... {
... "id" : 4,
... "status" : " fsdfsdfsdfdsf "
... }
... ]
... })
{
"acknowledged" : true,
"insertedId" : ObjectId("588b4984522a4f31ff6bc738")
}
Find inserted document
> db.getCollection('myCollectionName').findOne()
{
"_id" : ObjectId("588b4984522a4f31ff6bc738"),
"id" : 1,
"children" : [
{
"id" : 2,
"status" : " fsdfsdf "
},
{
"id" : 3,
"status" : " ffdfg "
},
{
"id" : 4,
"status" : " fsdfsdfsdfdsf "
}
]
}
I use findOne because I know in db only one document. In normal situation you need use find and pretty to find all document in collection
> db.getCollection('myCollectionName').find().pretty()
Find documents in collection and save cursor in variable
> var docs = db.getCollection('myCollectionName').find()
Run function for trim only field status in array children in documents
> docs.forEach(function (doc) {
... for (subDoc of doc.children) {
... if(typeof subDoc.status === 'string') {
... subDoc.status = subDoc.status.trim();
... }
... }
...
... db.getCollection('myCollectionName').save(doc);
... })
Improvement for production: find only documents with field children and check fields into document exists.
Check the result (find the document)
> db.getCollection('myCollectionName').findOne()
{
"_id" : ObjectId("588b4984522a4f31ff6bc738"),
"id" : 1,
"children" : [
{
"id" : 2,
"status" : "fsdfsdf"
},
{
"id" : 3,
"status" : "ffdfg"
},
{
"id" : 4,
"status" : "fsdfsdfsdfdsf"
}
]
}

Mongo nested query with keys

Need help on MongoDB nested query. Below is my mongo collection.
Preference collection
{
"_id" : "user123",
"preferences" : {
"product-1" : {
"frequency" : "Weekly",
"details" : {
"email" : {
"value" : "On"
}
}
},
"product-2" : {
"preferencesFor" : "mpc-other",
"preferencesForType" : "Product",
"details" : {
"email" : {
"value" : "Off"
}
}
},
"product-3" : {
"preferencesFor" : "mpc-other",
"preferencesForType" : "Product",
"details" : {
"email" : {
"value" : "On"
}
}
}
}
}
Product Collection
{
"_id" : "product-1",
"name" : "Geo-Magazine"
}
{
"_id" : "product-2",
"name" : "History-Magazine"
}
{
"_id" : "product-3",
"name" : "Science-Magazine"
}
product-1, product-2... are keys from a Map.
The keys are stored in another collection Product Collection.
Can I create a nested query to cross-reference the product keys from another table?
I need the output in the below table format. Please suggest.
user123 product-1 email On
user123 product-2 email Off
user123 product-3 email On
I tried the below but can't get result. Please suggest.
var cursor = db.productSummary.find();
while(cursor.hasNext()){
var sku = cursor.next()._id;
var skuCol = "preferences."+sku+".details.email";
var skuVal = "preferences."+sku+".details.email.value";
db.marketingPreferences.find( {}, {_id:1, skuCol:1, skuVal:1});
}
> var myCursor = db.productSummary.find();
> while(myCursor.hasNext()){
var sku = myCursor.next()._id;
var skuCol = "preferences."+sku+".details.email";
var skuVal = "$preferences."+sku+".details.email.value";
var result = db.marketingPreferences.aggregate([{"$project":{"_id":1,value:skuVal,preferences:{$literal: sku}}}],{allowDiskUse: true});
while(result.hasNext()){
printjson(result.next());
}
}
Result
{ "_id" : "user123", "preferences" : "product-1", "value" : "On" }
{ "_id" : "user123", "preferences" : "product-2", "value" : "Off" }
{ "_id" : "user123", "preferences" : "product-3", "value" : "On" }
There's a difference between MongoDB and normal SQL DB. Firstly, when you query a MongoDB collection, it doesn't return a row as it will in a SQL db. What you get here is a document similar to JSON.
Also when you use preferences.product-1.details.email : 1 it wont return you the word 'email', rather it will return you the value ie. {"value" : "On" }.
Using this: db.preference.find({},{"_id":1,"preferences.product1.details.email.value":1})
you will be able to get two details which are user123 and On and you can get product-1 from your previous query. You can store these values in a variable and keep printing them to obtain the table necessary. Also you would need another cursor to store the result of the second second query that you would do.
Here's what your query will produce if it was single standalone query:
> db.preference.find({},{"_id":1,"preferences.product1.details.email.value":1})
.pretty()
{
"_id": "user123",
"preferences": {
"product-1": {
"details": {
"email": {
"value": "On"
}
}
}
}
}
public static void test(){
MongoCollection<Document> collection = getDatadase().getCollection("product");
MongoCollection<Document> pref = getDatadase().getCollection("pref");
List<Document> allDocList = collection.find().into(new ArrayList<Document>());
for(Document doc:allDocList){
System.out.println(doc.get("_id"));
String preferences = doc.get("_id")+"";
String sku = "$preferences."+preferences+".details.email.value";
Document aggregation = new Document().append("$project", new Document().append("_id", 1).append("value", sku));
List<Document> pipeline = new ArrayList<Document>();
pipeline.add(aggregation);
List<Document> aggList = pref.aggregate(pipeline).into(new ArrayList<Document>());
for(Document doc1:aggList){
System.out.println(doc1.append("preferences", preferences));
}
}
}
This Will return
product-1
Document{{_id=user123, value=On, preferences=product-1}}
product-2
Document{{_id=user123, value=Off, preferences=product-2}}
product-3
Document{{_id=user123, value=On, preferences=product-3}}

Updating an array of objects with a new key in mongoDB

Similar to this question
Barrowing the data set, I have something similar to this:
{
'user_id':'{1231mjnD-32JIjn-3213}',
'name':'John',
'campaigns':
[
{
'campaign_id':3221,
'start_date':'12-01-2012',
},
{
'campaign_id':3222,
'start_date':'13-01-2012',
}
]
}
And I want to add a new key in the campaigns like so:
{
'user_id':'{1231mjnD-32JIjn-3213}',
'name':'John',
'campaigns':
[
{
'campaign_id':3221,
'start_date':'12-01-2012',
'worker_id': '00000'
},
{
'campaign_id':3222,
'start_date':'13-01-2012',
'worker_id': '00000'
}
]
}
How to insert/update a new key into an array of objects?
I want to add a new key into every object inside the array with a default value of 00000.
I have tried:
db.test.update({}, {$set: {'campaigns.worker_id': 00000}}, true, true)
db.test.update({}, {$set: {campaigns: {worker_id': 00000}}}, true, true)
Any suggestions?
I'm supposing that this operation will occur once, so you can use a script to handle it:
var docs = db.test.find();
for(var i in docs) {
var document = docs[i];
for(var j in document.campaigns) {
var campaign = document.campaigns[j];
campaign.worker_id = '00000';
}
db.test.save(document);
}
The script will iterate over all documents in your collection then over all campaigns in each document, setting the *worker_id* property.
At the end, each document is persisted.
db.test.update({}, {$set: {'campaigns.0.worker_id': 00000}}, true, true
this will update 0 element.
if you want to add a new key into every object inside the array you should use:
$unwind
example:
{
title : "this is my title" ,
author : "bob" ,
posted : new Date() ,
pageViews : 5 ,
tags : [ "fun" , "good" , "fun" ] ,
comments : [
{ author :"joe" , text : "this is cool" } ,
{ author :"sam" , text : "this is bad" }
],
other : { foo : 5 }
}
unwinding tags
db.article.aggregate(
{ $project : {
author : 1 ,
title : 1 ,
tags : 1
}},
{ $unwind : "$tags" }
);
result:
{
"result" : [
{
"_id" : ObjectId("4e6e4ef557b77501a49233f6"),
"title" : "this is my title",
"author" : "bob",
"tags" : "fun"
},
{
"_id" : ObjectId("4e6e4ef557b77501a49233f6"),
"title" : "this is my title",
"author" : "bob",
"tags" : "good"
},
{
"_id" : ObjectId("4e6e4ef557b77501a49233f6"),
"title" : "this is my title",
"author" : "bob",
"tags" : "fun"
}
],
"OK" : 1
}
After you could write simple updaiting query.