@dhyasama/totem-models 6.21.9 → 6.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/Organization.js +167 -128
- package/lib/Person.js +43 -0
- package/package.json +1 -1
- package/test/Organization.js +35 -2
- package/test/Person.js +26 -0
package/lib/Organization.js
CHANGED
|
@@ -402,6 +402,129 @@ module.exports = function(mongoose, config) {
|
|
|
402
402
|
|
|
403
403
|
};
|
|
404
404
|
|
|
405
|
+
var prepForSave = function prepForSave(doc) {
|
|
406
|
+
|
|
407
|
+
var cleanContactInfo = function cleanContactInfo(obj) {
|
|
408
|
+
|
|
409
|
+
var thereCanOnlyBeOne = function thereCanOnlyBeOne(items) {
|
|
410
|
+
|
|
411
|
+
var primaryItems = _.filter(items, function(item) { return item.primary; });
|
|
412
|
+
|
|
413
|
+
if (primaryItems.length > 1) {
|
|
414
|
+
|
|
415
|
+
_.each(primaryItems, function(item, index) {
|
|
416
|
+
// skip the first one (leave it primary) and mark the rest as not primary
|
|
417
|
+
if (index >= 1) item.primary = false;
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
return items;
|
|
423
|
+
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
if (!obj || !obj.contact) return;
|
|
427
|
+
|
|
428
|
+
if (obj.contact.address) {
|
|
429
|
+
|
|
430
|
+
// must have something meaningful
|
|
431
|
+
obj.contact.address = _.map(obj.contact.address, function(address) {
|
|
432
|
+
if (!address.city && !address.state && !address.country) return null;
|
|
433
|
+
else return address;
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
// remove emptiness and dedupe
|
|
437
|
+
obj.contact.address = _.uniq(_.compact(obj.contact.address), function(item) { return item.city + item.state + item.country; });
|
|
438
|
+
|
|
439
|
+
// only one primary
|
|
440
|
+
obj.contact.address = thereCanOnlyBeOne(obj.contact.address);
|
|
441
|
+
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
if (obj.contact.email) {
|
|
445
|
+
|
|
446
|
+
// must have something meaningful
|
|
447
|
+
obj.contact.email = _.map(doc.contact.email, function(item) {
|
|
448
|
+
if (!item.email) return null;
|
|
449
|
+
else return item;
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
// remove emptiness and dedupe
|
|
453
|
+
obj.contact.email = _.uniq(_.compact(obj.contact.email), function(item) { return item.email; });
|
|
454
|
+
|
|
455
|
+
// only one primary
|
|
456
|
+
obj.contact.email = thereCanOnlyBeOne(obj.contact.email);
|
|
457
|
+
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
if (obj.contact.phone) {
|
|
461
|
+
|
|
462
|
+
// must have something meaningful
|
|
463
|
+
obj.contact.phone = _.map(doc.contact.phone, function(item) {
|
|
464
|
+
if (!item.number) return null;
|
|
465
|
+
else return item;
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
// remove emptiness and dedupe
|
|
469
|
+
obj.contact.phone = _.uniq(_.compact(obj.contact.phone), function(item) { return item.number; });
|
|
470
|
+
|
|
471
|
+
// only one primary
|
|
472
|
+
obj.contact.phone = thereCanOnlyBeOne(obj.contact.phone);
|
|
473
|
+
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
};
|
|
477
|
+
|
|
478
|
+
var cleanPeople = function cleanPeople(obj) {
|
|
479
|
+
|
|
480
|
+
if (!obj || !obj.people) return;
|
|
481
|
+
|
|
482
|
+
// remove junk
|
|
483
|
+
obj.people = _.reject(obj.people, function(p) { return p.person == null; });
|
|
484
|
+
|
|
485
|
+
// dedupe
|
|
486
|
+
obj.people = _.uniq(obj.people, function(p) { return p.person._id ? p.person._id.toString() : p.person.toString(); });
|
|
487
|
+
|
|
488
|
+
};
|
|
489
|
+
|
|
490
|
+
var cleanWebsites = function cleanWebsites(obj) {
|
|
491
|
+
|
|
492
|
+
if (!obj) return;
|
|
493
|
+
|
|
494
|
+
// Format website
|
|
495
|
+
if (obj.website) {
|
|
496
|
+
obj.website = String(obj.website);
|
|
497
|
+
obj.website = obj.website.replace('http://', '').replace('https://', '').replace(/\/+$/, '');
|
|
498
|
+
obj.website = utils.getDomain(obj.website);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Format website aliases
|
|
502
|
+
if (obj.websiteAliases && obj.websiteAliases.length >= 1) {
|
|
503
|
+
obj.websiteAliases = _.map(obj.websiteAliases, function(alias) {
|
|
504
|
+
alias = String(alias);
|
|
505
|
+
alias = alias.replace('http://', '').replace('https://', '').replace(/\/+$/, '');
|
|
506
|
+
return utils.getDomain(alias);
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// Add website to website aliases
|
|
511
|
+
// There are unique constraints on website and website aliases
|
|
512
|
+
// This enables us to enforce uniqueness across both and across documents
|
|
513
|
+
if (obj.website && obj.websiteAliases) obj.websiteAliases.push(obj.website);
|
|
514
|
+
|
|
515
|
+
if (obj.websiteAliases) {
|
|
516
|
+
obj.websiteAliases = _.uniq(obj.websiteAliases);
|
|
517
|
+
obj.websiteAliases = _.compact(obj.websiteAliases);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
};
|
|
521
|
+
|
|
522
|
+
cleanContactInfo(doc);
|
|
523
|
+
cleanPeople(doc);
|
|
524
|
+
cleanWebsites(doc);
|
|
525
|
+
|
|
526
|
+
};
|
|
527
|
+
|
|
405
528
|
|
|
406
529
|
|
|
407
530
|
///////////////////////////////////////////////////////////////////////////////////////
|
|
@@ -870,13 +993,8 @@ module.exports = function(mongoose, config) {
|
|
|
870
993
|
|
|
871
994
|
Organization.methods.addDeal = function(deal) {
|
|
872
995
|
|
|
873
|
-
console.log('Organization.methods.addDeal');
|
|
874
|
-
console.log(deal);
|
|
875
|
-
|
|
876
996
|
var self = this;
|
|
877
997
|
|
|
878
|
-
console.log(self.deals);
|
|
879
|
-
|
|
880
998
|
// Validate inputs
|
|
881
999
|
if (!deal) throw new Error('deal is required');
|
|
882
1000
|
|
|
@@ -1453,6 +1571,49 @@ module.exports = function(mongoose, config) {
|
|
|
1453
1571
|
|
|
1454
1572
|
};
|
|
1455
1573
|
|
|
1574
|
+
Organization.statics.getByIdAsGlobal = function getByIdAsGlobal(id, options, cb) {
|
|
1575
|
+
|
|
1576
|
+
var self = this;
|
|
1577
|
+
|
|
1578
|
+
// Save original id so we can put it back when we're done
|
|
1579
|
+
var orginalCustomerId = config.CUSTOMER_ID;
|
|
1580
|
+
|
|
1581
|
+
// Switch to global
|
|
1582
|
+
config.CUSTOMER_ID = "GLOBAL_PROCESS";
|
|
1583
|
+
console.log('config.CUSTOMER_ID pre query', config.CUSTOMER_ID);
|
|
1584
|
+
|
|
1585
|
+
try {
|
|
1586
|
+
|
|
1587
|
+
self.findById(id, function(err, result) {
|
|
1588
|
+
|
|
1589
|
+
// Put original id back
|
|
1590
|
+
config.CUSTOMER_ID = orginalCustomerId;
|
|
1591
|
+
console.log('config.CUSTOMER_ID post query', config.CUSTOMER_ID);
|
|
1592
|
+
|
|
1593
|
+
if (err) { return cb(err, null); }
|
|
1594
|
+
|
|
1595
|
+
return cb(null, result);
|
|
1596
|
+
|
|
1597
|
+
});
|
|
1598
|
+
|
|
1599
|
+
|
|
1600
|
+
}
|
|
1601
|
+
catch(err) {
|
|
1602
|
+
|
|
1603
|
+
// Put original id back
|
|
1604
|
+
config.CUSTOMER_ID = orginalCustomerId;
|
|
1605
|
+
console.log('config.CUSTOMER_ID post query', config.CUSTOMER_ID);
|
|
1606
|
+
|
|
1607
|
+
console.log('ERROR WITH ORGANIZATION.GETBYIDGLOBAL');
|
|
1608
|
+
console.log('config.CUSTOMER_ID', config.CUSTOMER_ID);
|
|
1609
|
+
console.log(err);
|
|
1610
|
+
|
|
1611
|
+
return cb(err, null);
|
|
1612
|
+
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
};
|
|
1616
|
+
|
|
1456
1617
|
Organization.statics.getByIdRaw = function getByIdRaw(id, options, cb) {
|
|
1457
1618
|
|
|
1458
1619
|
// directly from mongo driver to avoid mongoose middlewares
|
|
@@ -1465,7 +1626,6 @@ module.exports = function(mongoose, config) {
|
|
|
1465
1626
|
|
|
1466
1627
|
if (err) return cb(err, null);
|
|
1467
1628
|
else if (!result) return cb(null, null);
|
|
1468
|
-
else if (result.people.length == 0) return cb(null, result);
|
|
1469
1629
|
|
|
1470
1630
|
// hydrate so we can use the populate method to get people
|
|
1471
1631
|
// note the hydrated version is not returned
|
|
@@ -1934,128 +2094,7 @@ module.exports = function(mongoose, config) {
|
|
|
1934
2094
|
|
|
1935
2095
|
Organization.pre('save', function(next) {
|
|
1936
2096
|
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
var cleanDoc = function cleanDoc(doc) {
|
|
1940
|
-
|
|
1941
|
-
var cleanContactInfo = function cleanContactInfo(obj) {
|
|
1942
|
-
|
|
1943
|
-
var thereCanOnlyBeOne = function thereCanOnlyBeOne(items) {
|
|
1944
|
-
|
|
1945
|
-
var primaryItems = _.filter(items, function(item) { return item.primary; });
|
|
1946
|
-
|
|
1947
|
-
if (primaryItems.length > 1) {
|
|
1948
|
-
|
|
1949
|
-
_.each(primaryItems, function(item, index) {
|
|
1950
|
-
// skip the first one (leave it primary) and mark the rest as not primary
|
|
1951
|
-
if (index >= 1) item.primary = false;
|
|
1952
|
-
});
|
|
1953
|
-
|
|
1954
|
-
}
|
|
1955
|
-
|
|
1956
|
-
return items;
|
|
1957
|
-
|
|
1958
|
-
};
|
|
1959
|
-
|
|
1960
|
-
if (!obj || !obj.contact) return;
|
|
1961
|
-
|
|
1962
|
-
if (obj.contact.address) {
|
|
1963
|
-
|
|
1964
|
-
// must have something meaningful
|
|
1965
|
-
obj.contact.address = _.map(obj.contact.address, function(address) {
|
|
1966
|
-
if (!address.city && !address.state && !address.country) return null;
|
|
1967
|
-
else return address;
|
|
1968
|
-
});
|
|
1969
|
-
|
|
1970
|
-
// remove emptiness and dedupe
|
|
1971
|
-
obj.contact.address = _.uniq(_.compact(obj.contact.address), function(item) { return item.city + item.state + item.country; });
|
|
1972
|
-
|
|
1973
|
-
// only one primary
|
|
1974
|
-
obj.contact.address = thereCanOnlyBeOne(obj.contact.address);
|
|
1975
|
-
|
|
1976
|
-
}
|
|
1977
|
-
|
|
1978
|
-
if (obj.contact.email) {
|
|
1979
|
-
|
|
1980
|
-
// must have something meaningful
|
|
1981
|
-
obj.contact.email = _.map(doc.contact.email, function(item) {
|
|
1982
|
-
if (!item.email) return null;
|
|
1983
|
-
else return item;
|
|
1984
|
-
});
|
|
1985
|
-
|
|
1986
|
-
// remove emptiness and dedupe
|
|
1987
|
-
obj.contact.email = _.uniq(_.compact(obj.contact.email), function(item) { return item.email; });
|
|
1988
|
-
|
|
1989
|
-
// only one primary
|
|
1990
|
-
obj.contact.email = thereCanOnlyBeOne(obj.contact.email);
|
|
1991
|
-
|
|
1992
|
-
}
|
|
1993
|
-
|
|
1994
|
-
if (obj.contact.phone) {
|
|
1995
|
-
|
|
1996
|
-
// must have something meaningful
|
|
1997
|
-
obj.contact.phone = _.map(doc.contact.phone, function(item) {
|
|
1998
|
-
if (!item.number) return null;
|
|
1999
|
-
else return item;
|
|
2000
|
-
});
|
|
2001
|
-
|
|
2002
|
-
// remove emptiness and dedupe
|
|
2003
|
-
obj.contact.phone = _.uniq(_.compact(obj.contact.phone), function(item) { return item.number; });
|
|
2004
|
-
|
|
2005
|
-
// only one primary
|
|
2006
|
-
obj.contact.phone = thereCanOnlyBeOne(obj.contact.phone);
|
|
2007
|
-
|
|
2008
|
-
}
|
|
2009
|
-
|
|
2010
|
-
};
|
|
2011
|
-
|
|
2012
|
-
var cleanPeople = function cleanPeople(obj) {
|
|
2013
|
-
|
|
2014
|
-
// remove junk
|
|
2015
|
-
obj.people = _.reject(obj.people, function(p) { return p.person == null; });
|
|
2016
|
-
|
|
2017
|
-
// dedupe
|
|
2018
|
-
obj.people = _.uniq(obj.people, function(p) { return p.person._id ? p.person._id.toString() : p.person.toString(); });
|
|
2019
|
-
|
|
2020
|
-
};
|
|
2021
|
-
|
|
2022
|
-
var cleanWebsites = function cleanWebsites(obj) {
|
|
2023
|
-
|
|
2024
|
-
// Format website
|
|
2025
|
-
if (obj.website) {
|
|
2026
|
-
obj.website = String(obj.website);
|
|
2027
|
-
obj.website = obj.website.replace('http://', '').replace('https://', '').replace(/\/+$/, '');
|
|
2028
|
-
obj.website = utils.getDomain(obj.website);
|
|
2029
|
-
}
|
|
2030
|
-
|
|
2031
|
-
// Format website aliases
|
|
2032
|
-
if (obj.websiteAliases && obj.websiteAliases.length >= 1) {
|
|
2033
|
-
obj.websiteAliases = _.map(obj.websiteAliases, function(alias) {
|
|
2034
|
-
alias = String(alias);
|
|
2035
|
-
alias = alias.replace('http://', '').replace('https://', '').replace(/\/+$/, '');
|
|
2036
|
-
return utils.getDomain(alias);
|
|
2037
|
-
});
|
|
2038
|
-
}
|
|
2039
|
-
|
|
2040
|
-
// Add website to website aliases
|
|
2041
|
-
// There are unique constraints on website and website aliases
|
|
2042
|
-
// This enables us to enforce uniqueness across both and across documents
|
|
2043
|
-
if (obj.website && obj.websiteAliases) obj.websiteAliases.push(obj.website);
|
|
2044
|
-
|
|
2045
|
-
if (obj.websiteAliases) {
|
|
2046
|
-
obj.websiteAliases = _.uniq(obj.websiteAliases);
|
|
2047
|
-
obj.websiteAliases = _.compact(obj.websiteAliases);
|
|
2048
|
-
}
|
|
2049
|
-
|
|
2050
|
-
};
|
|
2051
|
-
|
|
2052
|
-
cleanContactInfo(doc);
|
|
2053
|
-
cleanPeople(doc);
|
|
2054
|
-
cleanWebsites(doc);
|
|
2055
|
-
|
|
2056
|
-
};
|
|
2057
|
-
|
|
2058
|
-
cleanDoc(self);
|
|
2097
|
+
prepForSave(this);
|
|
2059
2098
|
|
|
2060
2099
|
return next();
|
|
2061
2100
|
|
package/lib/Person.js
CHANGED
|
@@ -757,6 +757,49 @@ module.exports = function(mongoose, config) {
|
|
|
757
757
|
|
|
758
758
|
};
|
|
759
759
|
|
|
760
|
+
Person.statics.getByIdAsGlobal = function getByIdAsGlobal(id, options, cb) {
|
|
761
|
+
|
|
762
|
+
var self = this;
|
|
763
|
+
|
|
764
|
+
// Save original id so we can put it back when we're done
|
|
765
|
+
var orginalCustomerId = config.CUSTOMER_ID;
|
|
766
|
+
|
|
767
|
+
// Switch to global
|
|
768
|
+
config.CUSTOMER_ID = "GLOBAL_PROCESS";
|
|
769
|
+
console.log('config.CUSTOMER_ID pre query', config.CUSTOMER_ID);
|
|
770
|
+
|
|
771
|
+
try {
|
|
772
|
+
|
|
773
|
+
self.findById(id, function(err, result) {
|
|
774
|
+
|
|
775
|
+
// Put original id back
|
|
776
|
+
config.CUSTOMER_ID = orginalCustomerId;
|
|
777
|
+
console.log('config.CUSTOMER_ID post query', config.CUSTOMER_ID);
|
|
778
|
+
|
|
779
|
+
if (err) { return cb(err, null); }
|
|
780
|
+
|
|
781
|
+
return cb(null, result);
|
|
782
|
+
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
|
|
786
|
+
}
|
|
787
|
+
catch(err) {
|
|
788
|
+
|
|
789
|
+
// Put original id back
|
|
790
|
+
config.CUSTOMER_ID = orginalCustomerId;
|
|
791
|
+
console.log('config.CUSTOMER_ID post query', config.CUSTOMER_ID);
|
|
792
|
+
|
|
793
|
+
console.log('ERROR WITH PERSON.GETBYIDGLOBAL');
|
|
794
|
+
console.log('config.CUSTOMER_ID', config.CUSTOMER_ID);
|
|
795
|
+
console.log(err);
|
|
796
|
+
|
|
797
|
+
return cb(err, null);
|
|
798
|
+
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
};
|
|
802
|
+
|
|
760
803
|
Person.statics.getByIdRaw = function (id, cb) {
|
|
761
804
|
|
|
762
805
|
// directly from mongo driver to avoid mongoose middlewares
|
package/package.json
CHANGED
package/test/Organization.js
CHANGED
|
@@ -23,7 +23,7 @@ var account;
|
|
|
23
23
|
var customer1, customer2;
|
|
24
24
|
var deal;
|
|
25
25
|
|
|
26
|
-
describe
|
|
26
|
+
describe('Organization', function() {
|
|
27
27
|
|
|
28
28
|
var org1, org2, org3, org4, org5;
|
|
29
29
|
var mergeId = new mongoose.Types.ObjectId();
|
|
@@ -78,6 +78,10 @@ describe.only('Organization', function() {
|
|
|
78
78
|
org2.social.facebook = 'https://facebook.com/abc';
|
|
79
79
|
org2.social.linkedin = 'http://www.linkedin.com/in/abc';
|
|
80
80
|
org2.social.twitter = 'twitter.com/abc';
|
|
81
|
+
org2.iLevel.push({
|
|
82
|
+
customer: new mongoose.Types.ObjectId(),
|
|
83
|
+
url: 'https://ilevel.com/test'
|
|
84
|
+
});
|
|
81
85
|
|
|
82
86
|
org3 = new Organization();
|
|
83
87
|
org3.name = 'Fudge 3';
|
|
@@ -675,6 +679,17 @@ describe.only('Organization', function() {
|
|
|
675
679
|
|
|
676
680
|
});
|
|
677
681
|
|
|
682
|
+
it('finds an org as global', function (done) {
|
|
683
|
+
|
|
684
|
+
Organization.getByIdAsGlobal(org2._id, {}, function (err, result) {
|
|
685
|
+
should.not.exist(err);
|
|
686
|
+
should.exist(result);
|
|
687
|
+
result.iLevel.length.should.equal(1);
|
|
688
|
+
done();
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
});
|
|
692
|
+
|
|
678
693
|
it('gets an org by id', function (done) {
|
|
679
694
|
|
|
680
695
|
Organization.getById(org1.id, {role: 'lp-full'}, function (err, org) {
|
|
@@ -710,7 +725,25 @@ describe.only('Organization', function() {
|
|
|
710
725
|
}
|
|
711
726
|
};
|
|
712
727
|
|
|
713
|
-
Organization.modify(org1._id, update, function (err, org) {
|
|
728
|
+
Organization.modify({ _id: org1._id }, update, function (err, org) {
|
|
729
|
+
should.not.exist(err);
|
|
730
|
+
should.exist(org);
|
|
731
|
+
org.name.should.equal('I updated my name!');
|
|
732
|
+
done();
|
|
733
|
+
});
|
|
734
|
+
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
it('modifies a company by id', function (done) {
|
|
738
|
+
|
|
739
|
+
var update = {
|
|
740
|
+
$set: {
|
|
741
|
+
'entered.by': 'Testy McTester 2',
|
|
742
|
+
'entered.on': new Date()
|
|
743
|
+
}
|
|
744
|
+
};
|
|
745
|
+
|
|
746
|
+
Organization.modifyById(org1._id, update, function (err, org) {
|
|
714
747
|
should.not.exist(err);
|
|
715
748
|
should.exist(org);
|
|
716
749
|
org.name.should.equal('I updated my name!');
|
package/test/Person.js
CHANGED
|
@@ -162,6 +162,21 @@ describe('Person', function() {
|
|
|
162
162
|
person5.name.first = 'Tim';
|
|
163
163
|
person5.name.last = 'Reynolds';
|
|
164
164
|
person5.slug = 'tim-reynolds';
|
|
165
|
+
person5.sources = [{
|
|
166
|
+
person: new mongoose.Types.ObjectId(),
|
|
167
|
+
customer: new mongoose.Types.ObjectId()
|
|
168
|
+
}];
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
// sources: [{
|
|
172
|
+
// _id: false,
|
|
173
|
+
// person: { type: Schema.ObjectId, ref: 'Person' },
|
|
174
|
+
// customer: { type: Schema.ObjectId, ref: 'Organization' },
|
|
175
|
+
// interactions: {
|
|
176
|
+
// calendar: { type: Number, required: false, default: 0 },
|
|
177
|
+
// email: { type: Number, required: false, default: 0 }
|
|
178
|
+
// }
|
|
179
|
+
// }],
|
|
165
180
|
|
|
166
181
|
Person.upsert(person2, 'test-user', function(err, person2) {
|
|
167
182
|
Person.upsert(person3, 'test-user', function(err, person3) {
|
|
@@ -845,6 +860,17 @@ describe('Person', function() {
|
|
|
845
860
|
|
|
846
861
|
});
|
|
847
862
|
|
|
863
|
+
it('finds a person as global', function (done) {
|
|
864
|
+
|
|
865
|
+
Person.getByIdAsGlobal(person5._id, {}, function (err, result) {
|
|
866
|
+
should.not.exist(err);
|
|
867
|
+
should.exist(result);
|
|
868
|
+
result.sources.length.should.equal(1);
|
|
869
|
+
done();
|
|
870
|
+
});
|
|
871
|
+
|
|
872
|
+
});
|
|
873
|
+
|
|
848
874
|
it('finds the primary email for a person', function(done) {
|
|
849
875
|
|
|
850
876
|
Person.getById(person.id, function(err, person) {
|